diff --git a/Command/GenerateCommand.php b/Command/GenerateCommand.php index 3a9706a3c5416f3fc5dd8994b33df16b510154a0..5a0edaa6ca0f04a9164cbe987988234846ec02ae 100644 --- a/Command/GenerateCommand.php +++ b/Command/GenerateCommand.php @@ -6,48 +6,12 @@ */ 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\Doctrine\EntityFinder; -use Irstea\PlantUmlBundle\Doctrine\FieldDecorator; -use Irstea\PlantUmlBundle\Finder\ClassFinder; -use Irstea\PlantUmlBundle\Finder\FilteringFinder; -use Irstea\PlantUmlBundle\Finder\FinderInterface; -use Irstea\PlantUmlBundle\Model\ClassFilterInterface; -use Irstea\PlantUmlBundle\Model\ClassVisitor; -use Irstea\PlantUmlBundle\Model\Decorator\AttributeDecorator; -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\MethodDecorator; -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\Graph; -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 @@ -56,21 +20,6 @@ use Symfony\Component\Security\Core\Exception\RuntimeException; */ class GenerateCommand extends ContainerAwareCommand { - /** - * @var string[] - */ - private $bundles; - - /** - * @var KernelInterface - */ - private $kernel; - - /** - * @var EntityManagerInterface - */ - private $entityManager; - protected function configure() { $this @@ -79,16 +28,6 @@ class GenerateCommand extends ContainerAwareCommand ->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 @@ -99,224 +38,15 @@ class GenerateCommand extends ContainerAwareCommand protected function execute(InputInterface $input, OutputInterface $output) { $name = $input->getArgument('graph'); - $graphs = $this->getContainer()->getParameter('irstea_plant_uml.graphs'); - if (!isset($graphs[$name])) { + $serviceId = "irstea_plant_uml.graph.$name"; + + if (!$this->getContainer()->has($serviceId)) { throw new InvalidArgumentException("Le graphe '$name' n'est pas défini."); } - $config = $graphs[$name]; - - list($finder, $filter) = $this->buildFinder($config['sources']); - - $graph = new Graph( - new ClassVisitor( - $this->buildDecorator($config['decoration'], $filter), - $this->buildFilter($config['layout']), - $this->buildNamespace($config['layout']['namespaces']) - ), - $finder - ); - - $graph->visitAll(); - $writer = new OutputWriter($output); + $graph = $this->getContainer()->get($serviceId); + $graph->visitAll(); $graph->writeTo($writer); } - - /** - * @param array $config - * @return FinderInterface - */ - protected function buildFinder(array $config) - { - switch($config['type']) { - case 'entities': - $finder = $this->buildEntityFinder($config['entity_manager']); - break; - case 'classes': - $finder = $this->buildClassFinder($config['directories']); - break; - } - - $filter = $this->buildFilter($config); - if (!$filter) { - return [$finder, null]; - } - - return [new FilteringFinder($finder, $filter), $filter]; - } - - /** - * @param array $directories - * @return FinderInterface - */ - protected function buildClassFinder(array $directories) - { - return new ClassFinder($this->parseDirectories($directories)); - } - - /** - * @param string $managerName - * @return FinderInterface - */ - protected function buildEntityFinder($managerName) - { - return new EntityFinder( - $this->getContainer()->get('doctrine')->getManager($managerName) - ); - } - - /** - * @param array $config - * @return DecoratorInterface - * @throws RuntimeException - */ - protected function buildDecorator(array $config, ClassFilterInterface $defaultFilter = null) - { - if (empty($config['decorators'])) { - return NullDecorator::instance(); - } - - $decorators = []; - foreach($config['decorators'] as $type) { - $decorators[] = $this->buildTypedDecorator($type); - } - - if (count($decorators) === 1) { - $decorator = $decorators[0]; - } else { - $decorator = new CompositeDecorator($decorators); - } - - $filter = $this->buildFilter($config) ?: $defaultFilter; - if ($filter) { - $decorator = new FilteringDecorator($decorator, $filter); - } - - return $decorator; - } - - /** - * @param type $type - * @return DecoratorInterface - */ - protected function buildTypedDecorator($type) - { - switch($type) { - case 'inheritance': - return new InheritanceDecorator(); - case 'interfaces': - return new InterfaceDecorator(); - case 'traits': - return new TraitDecorator(); - case 'attributes': - return new AttributeDecorator(); - case 'methods': - return new MethodDecorator(); - case 'entity': - return new EntityDecorator($this->entityManager->getMetadataFactory()); - case 'associations': - return new AssociationDecorator($this->entityManager->getMetadataFactory()); - case 'fields': - return new FieldDecorator($this->entityManager->getMetadataFactory()); - default: - return NullDecorator::instance(); - } - } - - /** - * @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: - 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; - } - -} \ No newline at end of file +} diff --git a/DependencyInjection/IrsteaPlantUmlExtension.php b/DependencyInjection/IrsteaPlantUmlExtension.php index ae45c05e1258cb4dbe8928230f980aa6437bdb25..72f476d7bd56ce1b9ab579d9ca7bd74b47653fcb 100644 --- a/DependencyInjection/IrsteaPlantUmlExtension.php +++ b/DependencyInjection/IrsteaPlantUmlExtension.php @@ -8,8 +8,18 @@ namespace Irstea\PlantUmlBundle\DependencyInjection; +use Irstea\PlantUmlBundle\Doctrine\EntityFinder; +use Irstea\PlantUmlBundle\Finder\ClassFinder; +use Irstea\PlantUmlBundle\Finder\FilteringFinder; +use Irstea\PlantUmlBundle\Model\ClassVisitor; +use Irstea\PlantUmlBundle\Model\Graph; +use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\HttpKernel\DependencyInjection\Extension; +use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\DefinitionDecorator; +use Symfony\Component\DependencyInjection\Extension\Extension; +use Symfony\Component\DependencyInjection\Loader; +use Symfony\Component\DependencyInjection\Reference; /** * Description of IrsteaPlantUmlExtension @@ -20,10 +30,192 @@ class IrsteaPlantUmlExtension extends Extension { public function load(array $configs, ContainerBuilder $container) { + $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); + $loader->load('services.yml'); + $configuration = new Configuration(); $config = $this->processConfiguration($configuration, $configs); $container->setParameter('irstea_plant_uml.binaries', $config['binaries']); - $container->setParameter('irstea_plant_uml.graphs', $config['graphs']); + + foreach($config['graphs'] as $key => $graph) { + $this->loadGraph($key, $graph, $container); + } + } + + public function loadGraph($key, array $config, ContainerBuilder $container) + { + $id = "irstea_plant_uml.graph.$key"; + + $emName = $config['sources']['entity_manager']; + $em = new Reference("doctrine.orm.${emName}_entity_manager"); + + list($source, $defaultFilter) = $this->loadSources($id, $em, $config['sources'], $container); + + $visitor = $this->addService( + $container, + "$id.visitor", + ClassVisitor::class, + [ + $this->loadDecorator($id, $em, $config['decoration'], $defaultFilter, $container), + $this->loadFilter($id, $config['layout'], $container), + $this->loadNamespace($id, $em, $config['layout']['namespaces'], $container) + ] + ); + + $container->setDefinition($id, new Definition(Graph::class, [$visitor, $source])) + ->setPublic(true) + ->setLazy(true); + } + + /** + * @param string $id + * @param array $config + * @param ContainerBuilder $container + * @return Refernce[] + */ + protected function loadSources($id, Reference $em, array $config, ContainerBuilder $container) + { + $finderId = "$id.finder"; + + $filter = $this->loadFilter($finderId, $config, $container); + if ($filter) { + $inner = $this->loadFinder("$finderId.inner", $em, $config, $container); + $finder = $this->addService($container, $finderId, FilteringFinder::class, [$inner, $filter]); + } else { + $finder = $this->loadFinder($finderId, $em, $config, $container); + } + + return [$finder, $filter]; + } + + /** + * @param string $id + * @param Reference $em + * @param array $config + * @param ContainerBuilder $container + * @return Reference + */ + protected function loadFinder($id, Reference $em, array $config, ContainerBuilder $container) + { + switch($config['type']) { + case 'entities': + return $this->addService($container, $id, EntityFinder::class, [$em]); + case 'classes': + return $this->addService($container, $id, ClassFinder::class, [$config['directories']]); + } + } + + /** + * + * @param string $id + * @param Reference $em + * @param array $config + * @param Reference $defaultFilter + * @param ContainerBuilder $container + * @return Reference + */ + protected function loadDecorator($id, Reference $em, array $config, Reference $defaultFilter, ContainerBuilder $container) + { + if (empty($config['decorators'])) { + return new Reference('irstea.plant_uml.decorator.null'); + } + + $decoratorId = "$id.decorator"; + + $decorators = []; + foreach($config['decorators'] as $i => $type) { + $decorators[] = $this->loadTypedDecorator("$decoratorId.$i", $em, $type, $container); + } + + if (count($decorators) === 1) { + $container->setAlias($decoratorId, "$decoratorId.0"); + } else { + $container + ->setDefinition($decoratorId, new DefinitionDecorator('irstea.plant_uml.decorator.composite.template')) + ->replaceArgument(0, $decorators); + } + + $filter = $this->loadFilter($decoratorId, $config, $container) ?: $defaultFilter; + if ($filter) { + $container + ->setDefinition("$decoratorId.decorator", new DefinitionDecorator('irstea.plant_uml.decorator.filtered.template')) + ->setDecoratedService($decoratorId, "inner_decorator") + ->setArguments([new Reference("inner_decorator"), $filter]); + } + + return new Reference($decoratorId); + } + + /** + * @param string $id + * @param Reference $em + * @param string $type + * @param ContainerBuilder $container + * @return Reference + */ + protected function loadTypedDecorator($id, Reference $em, $type, ContainerBuilder $container) + { + if (in_array($type, ['entity', 'associations', 'fields'])) { + $container + ->setDefinition($id, new DefinitionDecorator("irstea.plant_uml.decorator.$type.template")) + ->replaceArgument(0, $em); + return new Reference($id); + } + + return new Reference("irstea.plant_uml.decorator.$type"); + } + + /** + * @param string $id + * @param Reference $em + * @param string $type + * @param ContainerBuilder $container + * @return Reference + */ + protected function loadNamespace($id, Reference $em, $type, ContainerBuilder $container) + { + if ($type === "entities") { + $namespaceId = "$id.namespace"; + $container + ->setDefinition($namespaceId, new DefinitionDecorator('irstea.plant_uml.namespaces.entities.template')) + ->replaceArgument(0, $em); + return new Reference($namespaceId); + } + + return new Reference("irstea.plant_uml.namespaces.$type"); + } + + /** + * @param string $id + * @param array $config + * @param ContainerBuilder $container + * @return Reference + */ + protected function loadFilter($id, array $config, ContainerBuilder $container) + { + $filterId = "$id.filter"; + $container + ->setDefinition($filterId, new DefinitionDecorator("irstea.plant_uml.filter.template")) + ->setArguments([ + isset($config['include']) ? $config['include'] : [], + isset($config['exclude']) ? $config['exclude'] : [], + ]); + return new Reference($filterId); + } + + /** + * + * @param ContainerBuilder $container + * @param string $id + * @param Definition $def + * @return Reference + */ + protected function addService(ContainerBuilder $container, $id, $class, array $arguments = []) + { + $container + ->setDefinition($id, new Definition($class, $arguments)) + ->setPublic(false); + return new Reference($id); } } diff --git a/Doctrine/AbstractDoctrineDecorator.php b/Doctrine/AbstractDoctrineDecorator.php index 6494d51580210b78859e410a3556d85acfa7ddf6..2110ff71edd089210fece824da01557594e2fed8 100644 --- a/Doctrine/AbstractDoctrineDecorator.php +++ b/Doctrine/AbstractDoctrineDecorator.php @@ -8,6 +8,7 @@ namespace Irstea\PlantUmlBundle\Doctrine; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\ClassMetadataFactory; use Irstea\PlantUmlBundle\Model\ClassVisitorInterface; @@ -27,9 +28,9 @@ abstract class AbstractDoctrineDecorator implements DecoratorInterface */ protected $metadataFactory; - public function __construct(ClassMetadataFactory $metadataFactory) + public function __construct(EntityManagerInterface $manager) { - $this->metadataFactory = $metadataFactory; + $this->metadataFactory = $manager->getMetadataFactory(); } public function decorate(ReflectionClass $class, NodeInterface $node, ClassVisitorInterface $visitor) diff --git a/Doctrine/DoctrineNamespace.php b/Doctrine/DoctrineNamespace.php index 6281536fcb08247deca991b9abf4ce363afca02c..d4ee453920af7746d030eef1a4313905639f89ec 100644 --- a/Doctrine/DoctrineNamespace.php +++ b/Doctrine/DoctrineNamespace.php @@ -17,8 +17,10 @@ class DoctrineNamespace extends \Irstea\PlantUmlBundle\Model\Namespace_\MappedNa { const SEPARATOR = '::'; - public function __construct(array $entityNamespaces) + public function __construct(\Doctrine\ORM\EntityManagerInterface $em) { + $entityNamespaces = $em->getConfiguration()->getEntityNamespaces(); + $mapping = []; foreach($entityNamespaces as $alias => $namespace) { $mapping[$namespace.'\\'] = $alias.'::'; diff --git a/Factory/FilterFactory.php b/Factory/FilterFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..931dc838817ea587937aa6fc548b0630a79f8f1b --- /dev/null +++ b/Factory/FilterFactory.php @@ -0,0 +1,112 @@ +<?php + +/* + * © 2016 IRSTEA + * Guillaume Perréal <guillaume.perreal@irstea.fr> + * Tous droits réservés. + */ + +namespace Irstea\PlantUmlBundle\Factory; + +use Irstea\PlantUmlBundle\Model\ClassFilterInterface; +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 Symfony\Component\HttpKernel\KernelInterface; + +/** + * Description of FilterFactory + * + * @author Guillaume Perréal <guillaume.perreal@irstea.fr> + */ +class FilterFactory +{ + /** + * @var KernelInterface + */ + private $kernel; + + public function __construct(KernelInterface $kernel) + { + $this->kernel = $kernel; + } + + /** + * @param array $include + * @param array $exclude + * @return ClassFilterInterface + */ + public function create($include = [], $exclude = []) + { + $filters = []; + + if (!empty($include)) { + $filters[] = $this->createSubFilters($include, false); + } + if (!empty($exclude)) { + $filters[] = $this->createSubFilters($exclude, true); + } + $filters = array_merge($filters); + + switch(count($filters)) { + case 0: + return AcceptAllFilter::instance(); + case 1: + return $filters[0]; + default: + return new AllFilter($filters); + } + } + + protected function createSubFilters(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; + } +} diff --git a/Resources/config/services.yml b/Resources/config/services.yml new file mode 100644 index 0000000000000000000000000000000000000000..a55b5f2657e55e6494b6bc46a1513ab8dd1ff697 --- /dev/null +++ b/Resources/config/services.yml @@ -0,0 +1,81 @@ +parameters: ~ + +services: + irstea.plant_uml.filter.factory: + class: Irstea\PlantUmlBundle\Factory\FilterFactory + arguments: [@kernel] + + irstea.plant_uml.filter.template: + class: Irstea\PlantUmlBundle\Model\ClassFilterInterface + abstract: true + factory: ["@irstea.plant_uml.filter.factory", create] + arguments: [[], []] + + irstea.plant_uml.finder.classes.template: + class: Irstea\PlantUmlBundle\Finder\ClassFinder + abstract: true + arguments: [null] + + irstea.plant_uml.finder.entities.template: + class: Irstea\PlantUmlBundle\Doctrine\EntityFinder + abstract: true + arguments: [null] + + irstea.plant_uml.decorator.inheritance: + class: Irstea\PlantUmlBundle\Model\Decorator\InheritanceDecorator + + irstea.plant_uml.decorator.interfaces: + class: Irstea\PlantUmlBundle\Model\Decorator\InterfaceDecorator + + irstea.plant_uml.decorator.traits: + class: Irstea\PlantUmlBundle\Model\Decorator\TraitDecorator + + irstea.plant_uml.decorator.attributes: + class: Irstea\PlantUmlBundle\Model\Decorator\AttributeDecorator + + irstea.plant_uml.decorator.methods: + class: Irstea\PlantUmlBundle\Model\Decorator\MethodDecorator + + irstea.plant_uml.decorator.null: + class: Irstea\PlantUmlBundle\Model\Decorator\NullDecorator + + irstea.plant_uml.decorator.entity.template: + class: Irstea\PlantUmlBundle\Doctrine\EntityDecorator + abstract: true + arguments: [null] + + irstea.plant_uml.decorator.associations.template: + class: Irstea\PlantUmlBundle\Doctrine\AssociationDecorator + abstract: true + arguments: [null] + + irstea.plant_uml.decorator.fields.template: + class: Irstea\PlantUmlBundle\Doctrine\FieldDecorator + abstract: true + arguments: [null] + + irstea.plant_uml.decorator.filtered.template: + class: Irstea\PlantUmlBundle\Model\Decorator\FilteringDecorator + abstract: true + public: false + + irstea.plant_uml.decorator.composite.template: + class: Irstea\PlantUmlBundle\Model\Decorator\CompositeDecorator + abstract: true + public: false + arguments: [[]] + + irstea.plant_uml.namespaces.php: + class: Irstea\PlantUmlBundle\Model\Namespace_\Php\RootNamespace + + irstea.plant_uml.namespaces.php: + class: Irstea\PlantUmlBundle\Model\Namespace_\FlatNamespace + + irstea.plant_uml.namespaces.bundles: + class: Irstea\PlantUmlBundle\Model\Namespace_\BundleNamespace + arguments: ["%kernel.bundles%"] + + irstea.plant_uml.namespaces.entities.template: + class: Irstea\PlantUmlBundle\Doctrine\DoctrineNamespace + abstract: true + arguments: [null] diff --git a/composer.json b/composer.json index f7b8f9a51a28795b24b2bc1a6fe6c0a494817319..4c614a605b18880f3d8d4bda0e5265950ccfa371 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ { "type": "composer", "url": "http://istest.lyon.cemagref.fr/satis" } ], "require": { - "php": ">=5.4", + "php": ">=5.6", "symfony/framework-bundle": "^2.6", "doctrine/doctrine-bundle": "^1.6" },