diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md index 1ecd16712ab2f..ff147727d45a3 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md @@ -6,6 +6,7 @@ CHANGELOG * Add `DomCrawlerAssertionsTrait::assertSelectorCount(int $count, string $selector)` * Allow to avoid `limit` definition in a RateLimiter configuration when using the `no_limit` policy + * Add `--format` option to the `debug:config` command 6.2 --- diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDebugCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDebugCommand.php index c5078d1b5b401..b80bf4d0b0319 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDebugCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDebugCommand.php @@ -16,6 +16,7 @@ use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Completion\CompletionInput; use Symfony\Component\Console\Completion\CompletionSuggestions; +use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Exception\LogicException; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -40,13 +41,17 @@ class ConfigDebugCommand extends AbstractConfigCommand { protected function configure() { + $commentedHelpFormats = array_map(static fn (string $format): string => sprintf('%s', $format), $this->getAvailableFormatOptions()); + $helpFormats = implode('", "', $commentedHelpFormats); + $this ->setDefinition([ new InputArgument('name', InputArgument::OPTIONAL, 'The bundle name or the extension alias'), new InputArgument('path', InputArgument::OPTIONAL, 'The configuration option path'), new InputOption('resolve-env', null, InputOption::VALUE_NONE, 'Display resolved environment variable values instead of placeholders'), + new InputOption('format', null, InputOption::VALUE_REQUIRED, sprintf('The output format ("%s")', implode('", "', $this->getAvailableFormatOptions())), class_exists(Yaml::class) ? 'yaml' : 'json'), ]) - ->setHelp(<<<'EOF' + ->setHelp(<<%command.name% command dumps the current configuration for an extension/bundle. @@ -55,6 +60,11 @@ protected function configure() php %command.full_name% framework php %command.full_name% FrameworkBundle +The --format option specifies the format of the configuration, +this is either "{$helpFormats}". + + php %command.full_name% framework --format=json + For dumping a specific option, add its path as second argument: php %command.full_name% framework serializer.enabled @@ -92,12 +102,20 @@ protected function execute(InputInterface $input, OutputInterface $output): int $config = $this->getConfig($extension, $container, $input->getOption('resolve-env')); + $format = $input->getOption('format'); + + if ('yaml' === $format && !class_exists(Yaml::class)) { + $errorIo->error('Setting the "format" option to "yaml" requires the Symfony Yaml component. Try running "composer install symfony/yaml" or use "--format=json" instead.'); + + return 1; + } + if (null === $path = $input->getArgument('path')) { $io->title( sprintf('Current configuration for %s', $name === $extensionAlias ? sprintf('extension with alias "%s"', $extensionAlias) : sprintf('"%s"', $name)) ); - $io->writeln(Yaml::dump([$extensionAlias => $config], 10)); + $io->writeln($this->convertToFormat([$extensionAlias => $config], $format)); return 0; } @@ -112,11 +130,20 @@ protected function execute(InputInterface $input, OutputInterface $output): int $io->title(sprintf('Current configuration for "%s.%s"', $extensionAlias, $path)); - $io->writeln(Yaml::dump($config, 10)); + $io->writeln($this->convertToFormat($config, $format)); return 0; } + private function convertToFormat(mixed $config, string $format): string + { + return match ($format) { + 'yaml' => Yaml::dump($config, 10), + 'json' => json_encode($config, \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE), + default => throw new InvalidArgumentException(sprintf('Supported formats are "%s".', implode('", "', $this->getAvailableFormatOptions()))), + }; + } + private function compileContainer(): ContainerBuilder { $kernel = clone $this->getApplication()->getKernel(); @@ -194,6 +221,10 @@ public function complete(CompletionInput $input, CompletionSuggestions $suggesti } catch (LogicException) { } } + + if ($input->mustSuggestOptionValuesFor('format')) { + $suggestions->suggestValues($this->getAvailableFormatOptions()); + } } private function getAvailableBundles(bool $alias): array @@ -228,4 +259,9 @@ private static function buildPathsCompletion(array $paths, string $prefix = ''): return $completionPaths; } + + private function getAvailableFormatOptions(): array + { + return ['yaml', 'json']; + } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ConfigDebugCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ConfigDebugCommandTest.php index 09b99f82f7c64..ce4764be765ec 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ConfigDebugCommandTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ConfigDebugCommandTest.php @@ -13,6 +13,7 @@ use Symfony\Bundle\FrameworkBundle\Command\ConfigDebugCommand; use Symfony\Bundle\FrameworkBundle\Console\Application; +use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Output\NullOutput; use Symfony\Component\Console\Tester\CommandCompletionTester; @@ -50,6 +51,19 @@ public function testDumpBundleOption() $this->assertStringContainsString('foo', $tester->getDisplay()); } + public function testDumpWithUnsupportedFormat() + { + $tester = $this->createCommandTester(); + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Supported formats are "yaml", "json"'); + + $tester->execute([ + 'name' => 'test', + '--format' => 'xml', + ]); + } + public function testParametersValuesAreResolved() { $tester = $this->createCommandTester(); @@ -157,6 +171,8 @@ public function provideCompletionSuggestions(): \Generator 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']]; + + yield 'option --format' => [['--format', ''], ['yaml', 'json']]; } private function createCommandTester(): CommandTester