diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDumpReferenceCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDumpReferenceCommand.php index dfa604f7a85a..574b496c727b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDumpReferenceCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDumpReferenceCommand.php @@ -37,6 +37,7 @@ protected function configure() ->setName('config:dump-reference') ->setDefinition(array( new InputArgument('name', InputArgument::OPTIONAL, 'The Bundle name or the extension alias'), + new InputArgument('path', InputArgument::OPTIONAL, 'The configuration option path'), new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (yaml or xml)', 'yaml'), )) ->setDescription('Dumps the default configuration for an extension') @@ -54,6 +55,10 @@ protected function configure() When the option is not provided, yaml is used. php %command.full_name% FrameworkBundle --format=xml + +For dumping a specific option, add its path as second argument (only available for the yaml format): + + php %command.full_name% framework profiler.matcher EOF ) @@ -71,7 +76,10 @@ protected function execute(InputInterface $input, OutputInterface $output) if (null === $name = $input->getArgument('name')) { $this->listBundles($io); - $io->comment('Provide the name of a bundle as the first argument of this command to dump its default configuration. (e.g. config:dump-reference FrameworkBundle)'); + $io->comment(array( + 'Provide the name of a bundle as the first argument of this command to dump its default configuration. (e.g. config:dump-reference FrameworkBundle)', + 'For dumping a specific option, add its path as the second argument of this command. (e.g. config:dump-reference FrameworkBundle profiler.matcher to dump the framework.profiler.matcher configuration)', + )); return; } @@ -82,13 +90,26 @@ protected function execute(InputInterface $input, OutputInterface $output) $this->validateConfiguration($extension, $configuration); + $format = $input->getOption('format'); + $path = $input->getArgument('path'); + + if ($path !== null && 'yaml' !== $format) { + $io->error('The "path" option is only available for the "yaml" format.'); + + return 1; + } + if ($name === $extension->getAlias()) { $message = sprintf('Default configuration for extension with alias: "%s"', $name); } else { $message = sprintf('Default configuration for "%s"', $name); } - switch ($input->getOption('format')) { + if ($path !== null) { + $message .= sprintf(' at path "%s"', $path); + } + + switch ($format) { case 'yaml': $io->writeln(sprintf('# %s', $message)); $dumper = new YamlReferenceDumper(); @@ -102,6 +123,6 @@ protected function execute(InputInterface $input, OutputInterface $output) throw new \InvalidArgumentException('Only the yaml and xml formats are supported.'); } - $io->writeln($dumper->dump($configuration, $extension->getNamespace())); + $io->writeln(null === $path ? $dumper->dump($configuration, $extension->getNamespace()) : $dumper->dumpAtPath($configuration, $path)); } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/DependencyInjection/Config/CustomConfig.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/DependencyInjection/Config/CustomConfig.php index 8b4abb7a08d6..d3a9b2a1b88e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/DependencyInjection/Config/CustomConfig.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/DependencyInjection/Config/CustomConfig.php @@ -18,6 +18,13 @@ public function addConfiguration($rootNode) $rootNode ->children() ->scalarNode('custom')->end() + ->arrayNode('array') + ->children() + ->scalarNode('child1')->end() + ->scalarNode('child2')->end() + ->end() + ->end() + ->end() ->end() ; } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ConfigDumpReferenceCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ConfigDumpReferenceCommandTest.php index b0ac90c31f5f..3817afed170c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ConfigDumpReferenceCommandTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ConfigDumpReferenceCommandTest.php @@ -40,6 +40,39 @@ public function testDumpBundleName() $this->assertContains(' custom:', $tester->getDisplay()); } + public function testDumpAtPath() + { + $tester = $this->createCommandTester(); + $ret = $tester->execute(array( + 'name' => 'test', + 'path' => 'array', + )); + + $this->assertSame(0, $ret, 'Returns 0 in case of success'); + $this->assertSame(<<<'EOL' +# Default configuration for extension with alias: "test" at path "array" +array: + child1: ~ + child2: ~ + + +EOL + , $tester->getDisplay(true)); + } + + public function testDumpAtPathXml() + { + $tester = $this->createCommandTester(); + $ret = $tester->execute(array( + 'name' => 'test', + 'path' => 'array', + '--format' => 'xml', + )); + + $this->assertSame(1, $ret); + $this->assertContains('[ERROR] The "path" option is only available for the "yaml" format.', $tester->getDisplay()); + } + /** * @return CommandTester */ diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index 54ebc0f0335c..d7055b8f512a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -20,7 +20,7 @@ "symfony/cache": "~3.3", "symfony/class-loader": "~3.2", "symfony/dependency-injection": "~3.3", - "symfony/config": "~2.8|~3.0", + "symfony/config": "~3.3", "symfony/event-dispatcher": "~2.8|~3.0", "symfony/http-foundation": "~3.1", "symfony/http-kernel": "~3.3", diff --git a/src/Symfony/Component/Config/Definition/Dumper/YamlReferenceDumper.php b/src/Symfony/Component/Config/Definition/Dumper/YamlReferenceDumper.php index a47424938091..16076354db51 100644 --- a/src/Symfony/Component/Config/Definition/Dumper/YamlReferenceDumper.php +++ b/src/Symfony/Component/Config/Definition/Dumper/YamlReferenceDumper.php @@ -33,6 +33,32 @@ public function dump(ConfigurationInterface $configuration) return $this->dumpNode($configuration->getConfigTreeBuilder()->buildTree()); } + public function dumpAtPath(ConfigurationInterface $configuration, $path) + { + $rootNode = $node = $configuration->getConfigTreeBuilder()->buildTree(); + + foreach (explode('.', $path) as $step) { + if (!$node instanceof ArrayNode) { + throw new \UnexpectedValueException(sprintf('Unable to find node at path "%s.%s"', $rootNode->getName(), $path)); + } + + /** @var NodeInterface[] $children */ + $children = $node instanceof PrototypedArrayNode ? $this->getPrototypeChildren($node) : $node->getChildren(); + + foreach ($children as $child) { + if ($child->getName() === $step) { + $node = $child; + + continue 2; + } + } + + throw new \UnexpectedValueException(sprintf('Unable to find node at path "%s.%s"', $rootNode->getName(), $path)); + } + + return $this->dumpNode($node); + } + public function dumpNode(NodeInterface $node) { $this->reference = ''; diff --git a/src/Symfony/Component/Config/Tests/Definition/Dumper/YamlReferenceDumperTest.php b/src/Symfony/Component/Config/Tests/Definition/Dumper/YamlReferenceDumperTest.php index ede5a19d0dc2..44e161bb3e15 100644 --- a/src/Symfony/Component/Config/Tests/Definition/Dumper/YamlReferenceDumperTest.php +++ b/src/Symfony/Component/Config/Tests/Definition/Dumper/YamlReferenceDumperTest.php @@ -25,6 +25,61 @@ public function testDumper() $this->assertEquals($this->getConfigurationAsString(), $dumper->dump($configuration)); } + public function provideDumpAtPath() + { + return array( + 'Regular node' => array('scalar_true', << array('array', << array('array.child2', << array('cms_pages.page', << array('cms_pages.page.locale', <<assertSame(trim($expected), trim($dumper->dumpAtPath($configuration, $path))); + } + private function getConfigurationAsString() { return <<<'EOL'