An error occurred while loading the file. Please try again.
-
Guillaume Perréal authoredbc58e9ca
<?php
/*
* Copyright (C) 2015 IRSTEA
* All rights reserved.
*/
namespace Irstea\PlantUmlBundle\Command;
use Doctrine\ORM\EntityManagerInterface;
use Irstea\PlantUmlBundle\Doctrine\AssociationDecorator;
use Irstea\PlantUmlBundle\Doctrine\DoctrineNamespace;
use Irstea\PlantUmlBundle\Doctrine\EntityDecorator;
use Irstea\PlantUmlBundle\Model\ClassFilterInterface;
use Irstea\PlantUmlBundle\Model\ClassVisitor;
use Irstea\PlantUmlBundle\Model\Decorator\CompositeDecorator;
use Irstea\PlantUmlBundle\Model\Decorator\FilteringDecorator;
use Irstea\PlantUmlBundle\Model\Decorator\InheritanceDecorator;
use Irstea\PlantUmlBundle\Model\Decorator\InterfaceDecorator;
use Irstea\PlantUmlBundle\Model\Decorator\NullDecorator;
use Irstea\PlantUmlBundle\Model\Decorator\TraitDecorator;
use Irstea\PlantUmlBundle\Model\DecoratorInterface;
use Irstea\PlantUmlBundle\Model\Filter\AcceptAllFilter;
use Irstea\PlantUmlBundle\Model\Filter\Composite\AllFilter;
use Irstea\PlantUmlBundle\Model\Filter\DirectoryFilter;
use Irstea\PlantUmlBundle\Model\Filter\NamespaceFilter;
use Irstea\PlantUmlBundle\Model\Namespace_\BundleNamespace;
use Irstea\PlantUmlBundle\Model\Namespace_\FlatNamespace;
use Irstea\PlantUmlBundle\Model\Namespace_\Php\RootNamespace;
use Irstea\PlantUmlBundle\Model\NamespaceInterface;
use Irstea\PlantUmlBundle\Writer\OutputWriter;
use ReflectionClass;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Config\Definition\Exception\Exception;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\SplFileInfo;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\Security\Core\Exception\InvalidArgumentException;
use Symfony\Component\Security\Core\Exception\RuntimeException;
/**
* Description of ImportAffiliationCommand
*
* @author Guillaume Perréal <guillaume.perreal@irstea.fr>
*/
class GenerateCommand extends ContainerAwareCommand
{
/**
* @var string[]
*/
private $bundles;
/**
* @var KernelInterface
*/
private $kernel;
/**
* @var EntityManagerInterface
*/
private $entityManager;
protected function configure()
{
$this
->setName('irstea:plantuml:generate')
->setDescription("Génère un graphe en PlantUML.")
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
->addArgument('graph', InputArgument::REQUIRED, 'Nom du graphe à générer');
}
protected function initialize(InputInterface $input, OutputInterface $output)
{
parent::initialize($input, $output);
// @todo: DI
$this->bundles = $this->getContainer()->getParameter('kernel.bundles');
$this->kernel = $this->getContainer()->get('kernel');
$this->entityManager = $this->getContainer()->get('doctrine.orm.entity_manager');
}
/**
*
* @param InputInterface $input
* @param OutputInterface $output
*
* @SuppressWarnings(UnusedFormalParameter)
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$name = $input->getArgument('graph');
$graphs = $this->getContainer()->getParameter('irstea_plant_uml.graphs');
if (!isset($graphs[$name])) {
throw new InvalidArgumentException("Le graphe '$name' n'est pas défini.");
}
$config = $graphs[$name];
$classes = $this->findClasses($config['sources']);
if (empty($classes)) {
$output->writeln("Nothing to analyze.");
return 0;
}
$namespace = $this->buildNamespace($config['layout']['namespaces']);
$displayFilter = $this->buildFilter($config['layout']);
$decorator = $this->buildDecorator($config['decoration']);
$visitor = new ClassVisitor($decorator, $displayFilter, $namespace);
foreach($classes as $class) {
$visitor->visitClass($class);
}
$writer = new OutputWriter($output);
$writer->write("@startuml\n");
$visitor->outputTo($writer);
$writer->write("@enduml\n");
}
/**
* @param ReflectionClass[]
*/
protected function findClasses(array $config)
{
switch($config['type']) {
case 'entities':
$classes = $this->findEntities($config['entity_manager']);
break;
case 'classes':
$classes = $this->findClassesInDirectories($config['directories']);
break;
}
$filter = $this->buildFilter($config);
if ($filter) {
return array_filter($classes, [$filter, 'accept']);
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
}
return $classes;
}
/**
* @return ReflectionClass[]
*/
protected function findEntities($managerName)
{
$doctrine = $this->getContainer()->get('doctrine');
$this->entityManager = $doctrine->getManager($managerName);
$classes = [];
foreach($this->entityManager->getMetadataFactory()->getAllMetadata() as $metadata) {
$classes[$metadata->getName()] = $metadata->getReflectionClass();
}
return $classes;
}
/**
*
* @return ReflectionClass[]
*/
protected function findClassesInDirectories($directories)
{
$paths = $this->parseDirectories($directories);
$files = Finder::create()
->in($paths)
->files()
->name('*.php')
->getIterator();
foreach($files as $file)
{
/* @var $file SplFileInfo */
$path = $file->getPathname();
try {
irstea_plantmul_include($path);
} catch(Exception $ex) {
printf("%s: %s (%s)\n", $path, get_class($ex), $ex->getMessage());
}
}
$filter = new DirectoryFilter($paths);
$classes = [];
foreach(get_declared_classes() as $className) {
$class = new ReflectionClass($className);
if ($filter->accept($class)) {
$classes[$className] = $class;
}
}
return $classes;
}
/**
* @param array $config
* @return DecoratorInterface
* @throws RuntimeException
*/
protected function buildDecorator(array $config)
{
$decorators = [];
foreach($config['decorators'] as $decorator) {
switch($decorator) {
case 'inheritance':
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
$decorators[] = new InheritanceDecorator();
break;
case 'interfaces':
$decorators[] = new InterfaceDecorator();
break;
case 'traits':
$decorators[] = new TraitDecorator();
break;
case 'entity':
$decorators[] = new EntityDecorator($this->entityManager->getMetadataFactory());
break;
case 'associations':
$decorators[] = new AssociationDecorator($this->entityManager->getMetadataFactory());
break;
/*default:
throw new RuntimeException("Decorator '$decorator' not yet implemented");*/
}
}
if (empty($decorators)) {
return NullDecorator::instance();
}
if (count($decorators) === 1) {
$decorator = $decorators[0];
} else {
$decorator = new CompositeDecorator($decorators);
}
$filter = $this->buildFilter($config);
if ($filter) {
$decorator = new FilteringDecorator($decorator, $filter);
}
return $decorator;
}
/**
* @param string $config
* @return NamespaceInterface
*/
protected function buildNamespace($config)
{
switch($config) {
case 'php':
return new RootNamespace();
case 'flat':
return new FlatNamespace();
case 'entities':
return new DoctrineNamespace($this->entityManager->getConfiguration()->getEntityNamespaces());
case 'bundles':
return new BundleNamespace($this->bundles);
}
}
/**
* @param array $config
* @return ClassFilterInterface|null
*/
protected function buildFilter(array $config)
{
$filters = array_merge(
isset($config['include']) ? $this->buildSubFilters($config['include'], false) : [],
isset($config['exclude']) ? $this->buildSubFilters($config['exclude'], true) : []
);
switch(count($filters)) {
case 0:
return null;
case 1:
281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
return $filters[0];
default:
return new AllFilter($filters);
}
}
/**
* @param array $config
* @param boolean $notFound
* @return ClassFilterInterface|null
*/
protected function buildSubFilters(array $config, $notFound)
{
$filters = [];
if (!empty($config['directories'])) {
$paths = $this->parseDirectories($config['directories']);
$filters[] = new DirectoryFilter($paths, $notFound);
}
if (!empty($config['namespaces'])) {
$namespaces = $this->parseNamespaces($config['namespaces']);
$filters[] = new NamespaceFilter($namespaces, $notFound);
}
return $filters;
}
/**
* @param array $paths
* @return array
*/
protected function parseDirectories(array $paths)
{
$actualPaths = [];
foreach($paths as $path) {
if (preg_match('/^@(\w+)(.*)$/', $path, $groups)) {
$bundle = $this->kernel->getBundle($groups[1]);
$path = $bundle->getPath() . $groups[2];
}
$actualPaths[] = realpath($path);
}
return $actualPaths;
}
/**
* @param array $paths
* @return array
*/
protected function parseNamespaces(array $namespaces)
{
$actualNamespaces = [];
foreach($namespaces as $namespace) {
if (preg_match('/^@(\w+)(.*)$/', $namespace, $groups)) {
$bundle = $this->kernel->getBundle($groups[1]);
$namespace = $bundle->getNamespace() . $groups[2];
}
$actualNamespaces[] = $namespace;
}
return $actualNamespaces;
}
}
function irstea_plantmul_include($filepath)
{
@include_once($filepath);
}