From 9d172548f7e780a885e10688afa9975d03b4144a Mon Sep 17 00:00:00 2001 From: adev Date: Sat, 31 Mar 2018 14:16:19 +0200 Subject: [PATCH] Add debug autoconfigure to the container debug command Close #26295 --- .../Command/ContainerDebugCommand.php | 18 +++++++--- .../Console/Descriptor/Descriptor.php | 30 +++++++++++++++++ .../Console/Descriptor/JsonDescriptor.php | 16 +++++++++ .../Console/Descriptor/MarkdownDescriptor.php | 18 ++++++++++ .../Console/Descriptor/TextDescriptor.php | 15 +++++++++ .../Console/Descriptor/XmlDescriptor.php | 33 ++++++++++++++++++- .../Descriptor/AbstractDescriptorTest.php | 1 + .../Console/Descriptor/ObjectsProvider.php | 5 +++ .../Descriptor/builder_1_autoconfigure.json | 5 +++ .../Descriptor/builder_1_autoconfigure.md | 7 ++++ .../Descriptor/builder_1_autoconfigure.txt | 7 ++++ .../Descriptor/builder_1_autoconfigure.xml | 6 ++++ 12 files changed, 156 insertions(+), 5 deletions(-) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_autoconfigure.json create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_autoconfigure.md create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_autoconfigure.txt create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_autoconfigure.xml diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php index 9830609d969ad..cfc6d985f6d60 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php @@ -55,6 +55,7 @@ protected function configure() new InputOption('parameter', null, InputOption::VALUE_REQUIRED, 'Displays a specific parameter for an application'), new InputOption('parameters', null, InputOption::VALUE_NONE, 'Displays parameters for an application'), new InputOption('types', null, InputOption::VALUE_NONE, 'Displays types (classes/interfaces) available in the container'), + new InputOption('autoconfigure', null, InputOption::VALUE_NONE, 'Displays autoconfiguration interfaces for an application'), new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'), new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw description'), )) @@ -71,6 +72,10 @@ protected function configure() To see available types that can be used for autowiring, use the --types flag: php %command.full_name% --types + +To see available autoconfiguration interfaces, use the --autoconfigure flag: + + php %command.full_name% --autoconfigure By default, private services are hidden. You can display all services by using the --show-private flag: @@ -107,6 +112,9 @@ protected function execute(InputInterface $input, OutputInterface $output) $errorIo = $io->getErrorStyle(); $this->validateInput($input); + if ($input->getOption('autoconfigure')) { + @unlink($this->getApplication()->getKernel()->getContainer()->getParameter('debug.container.dump')); + } $object = $this->getContainerBuilder(); if ($input->getOption('types')) { @@ -121,6 +129,8 @@ protected function execute(InputInterface $input, OutputInterface $output) $options = array(); } elseif ($parameter = $input->getOption('parameter')) { $options = array('parameter' => $parameter); + } elseif ($input->getOption('autoconfigure')) { + $options = array('autoconfigure' => true, 'show_private' => $input->getOption('show-private')); } elseif ($input->getOption('tags')) { $options = array('group_by' => 'tags', 'show_private' => $input->getOption('show-private')); } elseif ($tag = $input->getOption('tag')) { @@ -139,7 +149,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $options['output'] = $io; $helper->describe($io, $object, $options); - if (!$input->getArgument('name') && !$input->getOption('tag') && !$input->getOption('parameter') && $input->isInteractive()) { + if (!$input->getArgument('name') && !$input->getOption('tag') && !$input->getOption('parameter') && !$input->getOption('autoconfigure') && $input->isInteractive()) { if ($input->getOption('tags')) { $errorIo->comment('To search for a specific tag, re-run this command with a search term. (e.g. debug:container --tag=form.type)'); } elseif ($input->getOption('parameters')) { @@ -157,7 +167,7 @@ protected function execute(InputInterface $input, OutputInterface $output) */ protected function validateInput(InputInterface $input) { - $options = array('tags', 'tag', 'parameters', 'parameter'); + $options = array('tags', 'tag', 'parameters', 'parameter', 'autoconfigure'); $optionsCount = 0; foreach ($options as $option) { @@ -168,9 +178,9 @@ protected function validateInput(InputInterface $input) $name = $input->getArgument('name'); if ((null !== $name) && ($optionsCount > 0)) { - throw new \InvalidArgumentException('The options tags, tag, parameters & parameter can not be combined with the service name argument.'); + throw new \InvalidArgumentException('The options tags, tag, parameters, parameter & autoconfigure can not be combined with the service name argument.'); } elseif ((null === $name) && $optionsCount > 1) { - throw new \InvalidArgumentException('The options tags, tag, parameters & parameter can not be combined together.'); + throw new \InvalidArgumentException('The options tags, tag, parameters, parameter & autoconfigure can not be combined together.'); } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/Descriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/Descriptor.php index 043b4fff6e078..1d0ae51ec0d32 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/Descriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/Descriptor.php @@ -50,6 +50,9 @@ public function describe(OutputInterface $output, $object, array $options = arra case $object instanceof ParameterBag: $this->describeContainerParameters($object, $options); break; + case $object instanceof ContainerBuilder && isset($options['autoconfigure']) && true === $options['autoconfigure']: + $this->describeContainerAutoconfiguringTags($object, $options); + break; case $object instanceof ContainerBuilder && isset($options['group_by']) && 'tags' === $options['group_by']: $this->describeContainerTags($object, $options); break; @@ -120,6 +123,11 @@ abstract protected function describeContainerParameters(ParameterBag $parameters */ abstract protected function describeContainerTags(ContainerBuilder $builder, array $options = array()); + /** + * Describes container autoconfiguring tags. + */ + abstract protected function describeContainerAutoconfiguringTags(ContainerBuilder $builder, array $options = array()); + /** * Describes a container service by its name. * @@ -265,6 +273,28 @@ protected function findDefinitionsByTag(ContainerBuilder $builder, $showPrivate) return $definitions; } + /** + * @param ContainerBuilder $builder + * + * @return array + */ + protected function getAutoconfiguredInstanceofByTag(ContainerBuilder $builder) + { + $autoconfiguredInstanceofByTag = array(); + + foreach ($builder->getAutoconfiguredInstanceof() as $key => $autoconfiguredInstanceof) { + foreach (array_keys($autoconfiguredInstanceof->getTags()) as $tag) { + if (!isset($autoconfiguredInstanceofByTag[$tag])) { + $autoconfiguredInstanceofByTag[$tag] = array($key); + } else { + $autoconfiguredInstanceofByTag[$tag][] = $key; + } + } + } + + return $autoconfiguredInstanceofByTag; + } + protected function sortParameters(ParameterBag $parameters) { $parameters = $parameters->all(); diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php index 7b87fcf8965cd..2a5afb3e266a8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php @@ -76,6 +76,22 @@ protected function describeContainerTags(ContainerBuilder $builder, array $optio $this->writeData($data, $options); } + /** + * {@inheritdoc} + */ + protected function describeContainerAutoconfiguringTags(ContainerBuilder $builder, array $options = array()) + { + $data = array(); + + $autoconfiguredInstanceofByTag = $this->getAutoconfiguredInstanceofByTag($builder); + + foreach ($autoconfiguredInstanceofByTag as $tag => $autoconfiguredInstanceofList) { + $data[$tag] = $autoconfiguredInstanceofByTag[$tag]; + } + + $this->writeData($data, $options); + } + /** * {@inheritdoc} */ diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php index 8836cc234bfb0..afe5af0d41787 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php @@ -94,6 +94,24 @@ protected function describeContainerTags(ContainerBuilder $builder, array $optio } } + /** + * {@inheritdoc} + */ + protected function describeContainerAutoconfiguringTags(ContainerBuilder $builder, array $options = array()) + { + $this->write("Container autoconfiguring Tags\n=============================="); + + $autoconfiguredInstanceofByTag = $this->getAutoconfiguredInstanceofByTag($builder); + + foreach ($autoconfiguredInstanceofByTag as $tag => $autoconfiguredInstanceofList) { + $this->write("\n\n".$tag."\n".str_repeat('-', strlen($tag))); + foreach ($autoconfiguredInstanceofList as $autoconfiguredInstanceof) { + $this->write("\n\n"); + $this->write(sprintf('- %s', $autoconfiguredInstanceof)); + } + } + } + /** * {@inheritdoc} */ diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php index cc9aa505731a5..6159dbd2926b3 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php @@ -136,6 +136,21 @@ protected function describeContainerTags(ContainerBuilder $builder, array $optio } } + /** + * {@inheritdoc} + */ + protected function describeContainerAutoconfiguringTags(ContainerBuilder $builder, array $options = array()) + { + $options['output']->title('Symfony Container Autoconfiguring Tags'); + + $autoconfiguredInstanceofByTag = $this->getAutoconfiguredInstanceofByTag($builder); + + foreach ($autoconfiguredInstanceofByTag as $tag => $autoconfiguredInstanceofList) { + $options['output']->section(sprintf('"%s" tag', $tag)); + $options['output']->listing($autoconfiguredInstanceofList); + } + } + /** * {@inheritdoc} */ diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php index 1e3148db9a697..b13209196e13c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php @@ -61,6 +61,14 @@ protected function describeContainerTags(ContainerBuilder $builder, array $optio $this->writeDocument($this->getContainerTagsDocument($builder, isset($options['show_private']) && $options['show_private'])); } + /** + * {@inheritdoc} + */ + protected function describeContainerAutoconfiguringTags(ContainerBuilder $builder, array $options = array()) + { + $this->writeDocument($this->getContainerAutoconfiguringTagsDocument($builder)); + } + /** * {@inheritdoc} */ @@ -141,7 +149,10 @@ private function writeDocument(\DOMDocument $dom) $this->write($dom->saveXML()); } - private function getRouteCollectionDocument(RouteCollection $routes): \DOMDocument + /** + * @return \DOMDocument + */ + private function getRouteCollectionDocument(RouteCollection $routes) { $dom = new \DOMDocument('1.0', 'UTF-8'); $dom->appendChild($routesXML = $dom->createElement('routes')); @@ -249,6 +260,26 @@ private function getContainerTagsDocument(ContainerBuilder $builder, bool $showP return $dom; } + private function getContainerAutoconfiguringTagsDocument(ContainerBuilder $builder): \DOMDocument + { + $dom = new \DOMDocument('1.0', 'UTF-8'); + $dom->appendChild($containerXML = $dom->createElement('tags')); + + $autoconfiguredInstanceofByTag = $this->getAutoconfiguredInstanceofByTag($builder); + + foreach ($autoconfiguredInstanceofByTag as $tag => $autoconfiguredInstanceofList) { + $containerXML->appendChild($tagXML = $dom->createElement('tag')); + $tagXML->setAttribute('name', $tag); + + foreach ($autoconfiguredInstanceofList as $autoconfiguredInstanceof) { + $tagXML->appendChild($autoconfiguredInstanceofXML = $dom->createElement('autoconfigured-instanceof')); + $autoconfiguredInstanceofXML->appendChild(new \DOMText($autoconfiguredInstanceof)); + } + } + + return $dom; + } + private function getContainerServiceDocument($service, string $id, ContainerBuilder $builder = null, bool $showArguments = false): \DOMDocument { $dom = new \DOMDocument('1.0', 'UTF-8'); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/AbstractDescriptorTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/AbstractDescriptorTest.php index ab5c95a7d8b85..1a68026399107 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/AbstractDescriptorTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/AbstractDescriptorTest.php @@ -218,6 +218,7 @@ private function getContainerBuilderDescriptionTestData(array $objects) 'tag1' => array('show_private' => true, 'tag' => 'tag1'), 'tags' => array('group_by' => 'tags', 'show_private' => true), 'arguments' => array('show_private' => false, 'show_arguments' => true), + 'autoconfigure' => array('autoconfigure' => true), ); $data = array(); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/ObjectsProvider.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/ObjectsProvider.php index ce5cc7880b27c..ef8215fa52804 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/ObjectsProvider.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/ObjectsProvider.php @@ -92,6 +92,7 @@ public static function getContainerBuilders() $builder1 = new ContainerBuilder(); $builder1->setDefinitions(self::getContainerDefinitions()); $builder1->setAliases(self::getContainerAliases()); + $builder1->registerForAutoconfiguration(AutoconfiguringInterface::class)->addTag('autoconfiguring_interface_tag'); return array('builder_1' => $builder1); } @@ -196,3 +197,7 @@ public function compile() return new CompiledRoute('', '#PATH_REGEX#', array(), array(), '#HOST_REGEX#'); } } + +interface AutoconfiguringInterface +{ +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_autoconfigure.json b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_autoconfigure.json new file mode 100644 index 0000000000000..f923ebc75412b --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_autoconfigure.json @@ -0,0 +1,5 @@ +{ + "autoconfiguring_interface_tag": [ + "Symfony\\Bundle\\FrameworkBundle\\Tests\\Console\\Descriptor\\AutoconfiguringInterface" + ] +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_autoconfigure.md b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_autoconfigure.md new file mode 100644 index 0000000000000..175fcde968c06 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_autoconfigure.md @@ -0,0 +1,7 @@ +Container autoconfiguring Tags +============================== + +autoconfiguring_interface_tag +----------------------------- + +- Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\AutoconfiguringInterface diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_autoconfigure.txt b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_autoconfigure.txt new file mode 100644 index 0000000000000..f63129efcc45b --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_autoconfigure.txt @@ -0,0 +1,7 @@ +Symfony Container Autoconfiguring Tags +====================================== + +"autoconfiguring_interface_tag" tag +----------------------------------- + + * Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\AutoconfiguringInterface diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_autoconfigure.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_autoconfigure.xml new file mode 100644 index 0000000000000..4e37a68eff94a --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_autoconfigure.xml @@ -0,0 +1,6 @@ + + + + Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\AutoconfiguringInterface + +