From 48be8575ea6c793629655c994e4c0fa1e45e2ebe Mon Sep 17 00:00:00 2001 From: Antoine Makdessi Date: Tue, 2 Apr 2024 18:49:32 +0200 Subject: [PATCH] [FrameworkBundle] Display aliases in `debug:container` command --- .../Bundle/FrameworkBundle/CHANGELOG.md | 1 + .../Command/ContainerDebugCommand.php | 2 + .../Console/Descriptor/JsonDescriptor.php | 37 ++++++++++++------- .../Console/Descriptor/MarkdownDescriptor.php | 12 +++++- .../Console/Descriptor/TextDescriptor.php | 11 +++++- .../Console/Descriptor/XmlDescriptor.php | 34 ++++++++++------- 6 files changed, 68 insertions(+), 29 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md index 52624c2cd173f..16f8d2d2b4cdb 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md @@ -13,6 +13,7 @@ CHANGELOG * Add `secrets:reveal` command * Add `rate_limiter` option to `http_client.default_options` and `http_client.scoped_clients` * Attach the workflow's configuration to the `workflow` tag + * Display aliases in `debug:container` command 7.0 --- diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php index df6aef5dd6b3e..1277b6ae63fc9 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php @@ -44,6 +44,7 @@ protected function configure(): void ->setDefinition([ new InputArgument('name', InputArgument::OPTIONAL, 'A service name (foo)'), new InputOption('show-arguments', null, InputOption::VALUE_NONE, 'Show arguments in services'), + new InputOption('with-aliases', null, InputOption::VALUE_NONE, 'Display aliases for a single service'), new InputOption('show-hidden', null, InputOption::VALUE_NONE, 'Show hidden (internal) services'), new InputOption('tag', null, InputOption::VALUE_REQUIRED, 'Show all services with a specific tag'), new InputOption('tags', null, InputOption::VALUE_NONE, 'Display tagged services for an application'), @@ -159,6 +160,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $helper = new DescriptorHelper(); $options['format'] = $input->getOption('format'); $options['show_arguments'] = $input->getOption('show-arguments'); + $options['with_aliases'] = $input->getOption('with-aliases'); $options['show_hidden'] = $input->getOption('show-hidden'); $options['raw_text'] = $input->getOption('raw'); $options['output'] = $io; diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php index 88cf4162c6c83..96cf2d32a2b66 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php @@ -79,7 +79,7 @@ protected function describeContainerService(object $service, array $options = [] if ($service instanceof Alias) { $this->describeContainerAlias($service, $options, $container); } elseif ($service instanceof Definition) { - $this->writeData($this->getContainerDefinitionData($service, isset($options['omit_tags']) && $options['omit_tags'], isset($options['show_arguments']) && $options['show_arguments'], $container, $options['id']), $options); + $this->writeData($this->getContainerDefinitionData($service, isset($options['omit_tags']) && $options['omit_tags'], isset($options['show_arguments']) && $options['show_arguments'], $container, $options['id'], isset($options['with_aliases']) && $options['with_aliases']), $options); } else { $this->writeData($service::class, $options); } @@ -93,6 +93,7 @@ protected function describeContainerServices(ContainerBuilder $container, array $showHidden = isset($options['show_hidden']) && $options['show_hidden']; $omitTags = isset($options['omit_tags']) && $options['omit_tags']; $showArguments = isset($options['show_arguments']) && $options['show_arguments']; + $withAliases = isset($options['with_aliases']) && $options['with_aliases']; $data = ['definitions' => [], 'aliases' => [], 'services' => []]; if (isset($options['filter'])) { @@ -112,7 +113,7 @@ protected function describeContainerServices(ContainerBuilder $container, array if ($service->hasTag('container.excluded')) { continue; } - $data['definitions'][$serviceId] = $this->getContainerDefinitionData($service, $omitTags, $showArguments, $container, $serviceId); + $data['definitions'][$serviceId] = $this->getContainerDefinitionData($service, $omitTags, $showArguments, $container, $serviceId, $withAliases); } else { $data['services'][$serviceId] = $service::class; } @@ -123,7 +124,7 @@ protected function describeContainerServices(ContainerBuilder $container, array protected function describeContainerDefinition(Definition $definition, array $options = [], ?ContainerBuilder $container = null): void { - $this->writeData($this->getContainerDefinitionData($definition, isset($options['omit_tags']) && $options['omit_tags'], isset($options['show_arguments']) && $options['show_arguments'], $container, $options['id'] ?? null), $options); + $this->writeData($this->getContainerDefinitionData($definition, isset($options['omit_tags']) && $options['omit_tags'], isset($options['show_arguments']) && $options['show_arguments'], $container, $options['id'] ?? null, isset($options['with_aliases']) && $options['with_aliases']), $options); } protected function describeContainerAlias(Alias $alias, array $options = [], ?ContainerBuilder $container = null): void @@ -135,7 +136,7 @@ protected function describeContainerAlias(Alias $alias, array $options = [], ?Co } $this->writeData( - [$this->getContainerAliasData($alias), $this->getContainerDefinitionData($container->getDefinition((string) $alias), isset($options['omit_tags']) && $options['omit_tags'], isset($options['show_arguments']) && $options['show_arguments'], $container, (string) $alias)], + [$this->getContainerAliasData($alias), $this->getContainerDefinitionData($container->getDefinition((string) $alias), isset($options['omit_tags']) && $options['omit_tags'], isset($options['show_arguments']) && $options['show_arguments'], $container, (string) $alias, isset($options['with_aliases']) && $options['with_aliases'])], array_merge($options, ['id' => (string) $alias]) ); } @@ -245,7 +246,7 @@ protected function sortParameters(ParameterBag $parameters): array return $sortedParameters; } - private function getContainerDefinitionData(Definition $definition, bool $omitTags = false, bool $showArguments = false, ?ContainerBuilder $container = null, ?string $id = null): array + private function getContainerDefinitionData(Definition $definition, bool $omitTags = false, bool $showArguments = false, ?ContainerBuilder $container = null, ?string $id = null, bool $withAliases = false): array { $data = [ 'class' => (string) $definition->getClass(), @@ -270,7 +271,7 @@ private function getContainerDefinitionData(Definition $definition, bool $omitTa } if ($showArguments) { - $data['arguments'] = $this->describeValue($definition->getArguments(), $omitTags, $showArguments, $container, $id); + $data['arguments'] = $this->describeValue($definition->getArguments(), $omitTags, $showArguments, $container, $id, $withAliases); } $data['file'] = $definition->getFile(); @@ -418,12 +419,12 @@ private function getCallableData(mixed $callable): array throw new \InvalidArgumentException('Callable is not describable.'); } - private function describeValue($value, bool $omitTags, bool $showArguments, ?ContainerBuilder $container = null, ?string $id = null): mixed + private function describeValue($value, bool $omitTags, bool $showArguments, ?ContainerBuilder $container = null, ?string $id = null, bool $withAliases = false): mixed { if (\is_array($value)) { $data = []; foreach ($value as $k => $v) { - $data[$k] = $this->describeValue($v, $omitTags, $showArguments, $container, $id); + $data[$k] = $this->describeValue($v, $omitTags, $showArguments, $container, $id, $withAliases); } return $data; @@ -434,10 +435,20 @@ private function describeValue($value, bool $omitTags, bool $showArguments, ?Con } if ($value instanceof Reference) { - return [ - 'type' => 'service', - 'id' => (string) $value, - ]; + $node = $container?->getCompiler()->getServiceReferenceGraph()->getNode((string) $value); + + if ($withAliases && $node?->getValue()?->getClass()) { + return [ + 'type' => 'service', + 'id' => (string) $value, + 'alias' => $node->getValue()->getClass(), + ]; + } else { + return [ + 'type' => 'service', + 'id' => (string) $value, + ]; + } } if ($value instanceof AbstractArgument) { @@ -449,7 +460,7 @@ private function describeValue($value, bool $omitTags, bool $showArguments, ?Con } if ($value instanceof Definition) { - return $this->getContainerDefinitionData($value, $omitTags, $showArguments, $container, $id); + return $this->getContainerDefinitionData($value, $omitTags, $showArguments, $container, $id, $withAliases); } return $value; diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php index 7965990bdf207..19b814f530f15 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php @@ -232,7 +232,17 @@ protected function describeContainerDefinition(Definition $definition, array $op } if (isset($options['show_arguments']) && $options['show_arguments']) { - $output .= "\n".'- Arguments: '.($definition->getArguments() ? 'yes' : 'no'); + if ($definition->getArguments()) { + foreach ($definition->getArguments() as $argument) { + $output .= "\n".'- Argument: `'.$argument.'`'; + if (isset($options['with_aliases']) && $options['with_aliases']) { + $node = $container?->getCompiler()?->getServiceReferenceGraph()?->getNode((string) $argument); + $output .= "\n".' - Alias: '.$node?->getValue()?->getClass(); + } + } + } else { + $output .= "\n".'- Arguments: no'; + } } if ($definition->getFile()) { diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php index d728128ce9106..37c707de5af58 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php @@ -352,6 +352,7 @@ protected function describeContainerDefinition(Definition $definition, array $op } $showArguments = isset($options['show_arguments']) && $options['show_arguments']; + $withAliases = isset($options['with_aliases']) && $options['with_aliases']; $argumentsInformation = []; if ($showArguments && ($arguments = $definition->getArguments())) { foreach ($arguments as $argument) { @@ -359,7 +360,15 @@ protected function describeContainerDefinition(Definition $definition, array $op $argument = $argument->getValues()[0]; } if ($argument instanceof Reference) { - $argumentsInformation[] = sprintf('Service(%s)', (string) $argument); + $node = $container?->getCompiler()?->getServiceReferenceGraph()?->getNode((string) $argument); + if ($withAliases && $node?->getValue()?->getClass()) { + $argumentsInformation[] = vsprintf('Alias(%s, Service(%s))', [ + $node->getValue()->getClass(), + (string) $argument, + ]); + } else { + $argumentsInformation[] = sprintf('Service(%s)', (string) $argument); + } } elseif ($argument instanceof IteratorArgument) { if ($argument instanceof TaggedIteratorArgument) { $argumentsInformation[] = sprintf('Tagged Iterator for "%s"%s', $argument->getTag(), $options['is_debug'] ? '' : sprintf(' (%d element(s))', \count($argument->getValues()))); diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php index c52b196674364..426f3b120797a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php @@ -59,17 +59,17 @@ protected function describeContainerService(object $service, array $options = [] throw new \InvalidArgumentException('An "id" option must be provided.'); } - $this->writeDocument($this->getContainerServiceDocument($service, $options['id'], $container, isset($options['show_arguments']) && $options['show_arguments'])); + $this->writeDocument($this->getContainerServiceDocument($service, $options['id'], $container, isset($options['show_arguments']) && $options['show_arguments'], isset($options['with_aliases']) && $options['with_aliases'])); } protected function describeContainerServices(ContainerBuilder $container, array $options = []): void { - $this->writeDocument($this->getContainerServicesDocument($container, $options['tag'] ?? null, isset($options['show_hidden']) && $options['show_hidden'], isset($options['show_arguments']) && $options['show_arguments'], $options['filter'] ?? null, $options['id'] ?? null)); + $this->writeDocument($this->getContainerServicesDocument($container, $options['tag'] ?? null, isset($options['show_hidden']) && $options['show_hidden'], isset($options['show_arguments']) && $options['show_arguments'], $options['filter'] ?? null, $options['id'] ?? null, isset($options['with_aliases']) && $options['with_aliases'])); } protected function describeContainerDefinition(Definition $definition, array $options = [], ?ContainerBuilder $container = null): void { - $this->writeDocument($this->getContainerDefinitionDocument($definition, $options['id'] ?? null, isset($options['omit_tags']) && $options['omit_tags'], isset($options['show_arguments']) && $options['show_arguments'], $container)); + $this->writeDocument($this->getContainerDefinitionDocument($definition, $options['id'] ?? null, isset($options['omit_tags']) && $options['omit_tags'], isset($options['show_arguments']) && $options['show_arguments'], $container, isset($options['with_aliases']) && $options['with_aliases'])); } protected function describeContainerAlias(Alias $alias, array $options = [], ?ContainerBuilder $container = null): void @@ -268,17 +268,17 @@ private function getContainerTagsDocument(ContainerBuilder $container, bool $sho return $dom; } - private function getContainerServiceDocument(object $service, string $id, ?ContainerBuilder $container = null, bool $showArguments = false): \DOMDocument + private function getContainerServiceDocument(object $service, string $id, ?ContainerBuilder $container = null, bool $showArguments = false, bool $withAliases = false): \DOMDocument { $dom = new \DOMDocument('1.0', 'UTF-8'); if ($service instanceof Alias) { $dom->appendChild($dom->importNode($this->getContainerAliasDocument($service, $id)->childNodes->item(0), true)); if ($container) { - $dom->appendChild($dom->importNode($this->getContainerDefinitionDocument($container->getDefinition((string) $service), (string) $service, false, $showArguments, $container)->childNodes->item(0), true)); + $dom->appendChild($dom->importNode($this->getContainerDefinitionDocument($container->getDefinition((string) $service), (string) $service, false, $showArguments, $container, $withAliases)->childNodes->item(0), true)); } } elseif ($service instanceof Definition) { - $dom->appendChild($dom->importNode($this->getContainerDefinitionDocument($service, $id, false, $showArguments, $container)->childNodes->item(0), true)); + $dom->appendChild($dom->importNode($this->getContainerDefinitionDocument($service, $id, false, $showArguments, $container, $withAliases)->childNodes->item(0), true)); } else { $dom->appendChild($serviceXML = $dom->createElement('service')); $serviceXML->setAttribute('id', $id); @@ -288,7 +288,7 @@ private function getContainerServiceDocument(object $service, string $id, ?Conta return $dom; } - private function getContainerServicesDocument(ContainerBuilder $container, ?string $tag = null, bool $showHidden = false, bool $showArguments = false, ?callable $filter = null, ?string $id = null): \DOMDocument + private function getContainerServicesDocument(ContainerBuilder $container, ?string $tag = null, bool $showHidden = false, bool $showArguments = false, ?callable $filter = null, ?string $id = null, bool $withAliases = false): \DOMDocument { $dom = new \DOMDocument('1.0', 'UTF-8'); $dom->appendChild($containerXML = $dom->createElement('container')); @@ -311,14 +311,14 @@ private function getContainerServicesDocument(ContainerBuilder $container, ?stri continue; } - $serviceXML = $this->getContainerServiceDocument($service, $serviceId, null, $showArguments); + $serviceXML = $this->getContainerServiceDocument($service, $serviceId, null, $showArguments, $withAliases); $containerXML->appendChild($containerXML->ownerDocument->importNode($serviceXML->childNodes->item(0), true)); } return $dom; } - private function getContainerDefinitionDocument(Definition $definition, ?string $id = null, bool $omitTags = false, bool $showArguments = false, ?ContainerBuilder $container = null): \DOMDocument + private function getContainerDefinitionDocument(Definition $definition, ?string $id = null, bool $omitTags = false, bool $showArguments = false, ?ContainerBuilder $container = null, bool $withAliases = false): \DOMDocument { $dom = new \DOMDocument('1.0', 'UTF-8'); $dom->appendChild($serviceXML = $dom->createElement('definition')); @@ -379,7 +379,7 @@ private function getContainerDefinitionDocument(Definition $definition, ?string } if ($showArguments) { - foreach ($this->getArgumentNodes($definition->getArguments(), $dom, $container) as $node) { + foreach ($this->getArgumentNodes($definition->getArguments(), $dom, $container, $withAliases) as $node) { $serviceXML->appendChild($node); } } @@ -418,7 +418,7 @@ private function getContainerDefinitionDocument(Definition $definition, ?string /** * @return \DOMNode[] */ - private function getArgumentNodes(array $arguments, \DOMDocument $dom, ?ContainerBuilder $container = null): array + private function getArgumentNodes(array $arguments, \DOMDocument $dom, ?ContainerBuilder $container = null, bool $withAliases = false): array { $nodes = []; @@ -434,23 +434,29 @@ private function getArgumentNodes(array $arguments, \DOMDocument $dom, ?Containe } if ($argument instanceof Reference) { + $node = $container?->getCompiler()?->getServiceReferenceGraph()?->getNode((string) $argument); + + if ($withAliases && $node?->getValue()?->getClass()) { + $argumentXML->setAttribute('alias', $node->getValue()->getClass()); + } + $argumentXML->setAttribute('type', 'service'); $argumentXML->setAttribute('id', (string) $argument); } elseif ($argument instanceof IteratorArgument || $argument instanceof ServiceLocatorArgument) { $argumentXML->setAttribute('type', $argument instanceof IteratorArgument ? 'iterator' : 'service_locator'); - foreach ($this->getArgumentNodes($argument->getValues(), $dom, $container) as $childArgumentXML) { + foreach ($this->getArgumentNodes($argument->getValues(), $dom, $container, $withAliases) as $childArgumentXML) { $argumentXML->appendChild($childArgumentXML); } } elseif ($argument instanceof Definition) { - $argumentXML->appendChild($dom->importNode($this->getContainerDefinitionDocument($argument, null, false, true, $container)->childNodes->item(0), true)); + $argumentXML->appendChild($dom->importNode($this->getContainerDefinitionDocument($argument, null, false, true, $container, $withAliases)->childNodes->item(0), true)); } elseif ($argument instanceof AbstractArgument) { $argumentXML->setAttribute('type', 'abstract'); $argumentXML->appendChild(new \DOMText($argument->getText())); } elseif (\is_array($argument)) { $argumentXML->setAttribute('type', 'collection'); - foreach ($this->getArgumentNodes($argument, $dom, $container) as $childArgumentXML) { + foreach ($this->getArgumentNodes($argument, $dom, $container, $withAliases) as $childArgumentXML) { $argumentXML->appendChild($childArgumentXML); } } elseif ($argument instanceof \UnitEnum) {