diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDebugCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDebugCommand.php index e88de6e31f257..8a8f2355b0365 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDebugCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDebugCommand.php @@ -13,6 +13,8 @@ use Symfony\Component\Config\Definition\ConfigurationInterface; use Symfony\Component\Config\Definition\Processor; +use Symfony\Component\Console\Completion\CompletionInput; +use Symfony\Component\Console\Completion\CompletionSuggestions; use Symfony\Component\Console\Exception\LogicException; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -94,11 +96,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $extensionAlias = $extension->getAlias(); $container = $this->compileContainer(); - $config = $container->resolveEnvPlaceholders( - $container->getParameterBag()->resolveValue( - $this->getConfigForExtension($extension, $container) - ) - ); + $config = $this->getConfig($extension, $container); if (null === $path = $input->getArgument('path')) { $io->title( @@ -188,4 +186,55 @@ private function getConfigForExtension(ExtensionInterface $extension, ContainerB return (new Processor())->processConfiguration($configuration, $configs); } + + public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void + { + if ($input->mustSuggestArgumentValuesFor('name')) { + $suggestions->suggestValues($this->getAvailableBundles(!preg_match('/^[A-Z]/', $input->getCompletionValue()))); + + return; + } + + if ($input->mustSuggestArgumentValuesFor('path') && null !== $name = $input->getArgument('name')) { + try { + $config = $this->getConfig($this->findExtension($name), $this->compileContainer()); + $paths = array_keys(self::buildPathsCompletion($config)); + $suggestions->suggestValues($paths); + } catch (LogicException $e) { + } + } + } + + private function getAvailableBundles(bool $alias): array + { + $availableBundles = []; + foreach ($this->getApplication()->getKernel()->getBundles() as $bundle) { + $availableBundles[] = $alias ? $bundle->getContainerExtension()->getAlias() : $bundle->getName(); + } + + return $availableBundles; + } + + private function getConfig(ExtensionInterface $extension, ContainerBuilder $container) + { + return $container->resolveEnvPlaceholders( + $container->getParameterBag()->resolveValue( + $this->getConfigForExtension($extension, $container) + ) + ); + } + + private static function buildPathsCompletion(array $paths, string $prefix = ''): array + { + $completionPaths = []; + foreach ($paths as $key => $values) { + if (\is_array($values)) { + $completionPaths = $completionPaths + self::buildPathsCompletion($values, $prefix.$key.'.'); + } else { + $completionPaths[$prefix.$key] = null; + } + } + + return $completionPaths; + } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ConfigDebugCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ConfigDebugCommandTest.php index 0df853997c59a..8135f4dcfe419 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ConfigDebugCommandTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ConfigDebugCommandTest.php @@ -11,9 +11,11 @@ namespace Symfony\Bundle\FrameworkBundle\Tests\Functional; +use Symfony\Bundle\FrameworkBundle\Command\ConfigDebugCommand; use Symfony\Bundle\FrameworkBundle\Console\Application; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Output\NullOutput; +use Symfony\Component\Console\Tester\CommandCompletionTester; use Symfony\Component\Console\Tester\CommandTester; /** @@ -111,6 +113,31 @@ public function testDumpThrowsExceptionWhenDefaultConfigFallbackIsImpossible() $tester->execute(['name' => 'ExtensionWithoutConfigTestBundle']); } + /** + * @dataProvider provideCompletionSuggestions + */ + public function testComplete(array $input, array $expectedSuggestions) + { + $this->application->add(new ConfigDebugCommand()); + + $tester = new CommandCompletionTester($this->application->get('debug:config')); + + $suggestions = $tester->complete($input); + + foreach ($expectedSuggestions as $expectedSuggestion) { + $this->assertContains($expectedSuggestion, $suggestions); + } + } + + public function provideCompletionSuggestions(): \Generator + { + yield 'name' => [[''], ['default_config_test', 'extension_without_config_test', 'framework', 'test']]; + + yield 'name (started CamelCase)' => [['Fra'], ['DefaultConfigTestBundle', 'ExtensionWithoutConfigTestBundle', 'FrameworkBundle', 'TestBundle']]; + + yield 'name with existing path' => [['framework', ''], ['secret', 'router.resource', 'router.utf8', 'router.enabled', 'validation.enabled', 'default_locale']]; + } + private function createCommandTester(): CommandTester { $command = $this->application->find('debug:config');