diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDumpReferenceCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDumpReferenceCommand.php new file mode 100644 index 0000000000..3243f2ee45 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDumpReferenceCommand.php @@ -0,0 +1,261 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Command; + +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Config\Definition\NodeInterface; +use Symfony\Component\Config\Definition\ArrayNode; +use Symfony\Component\Config\Definition\PrototypedArrayNode; +use Symfony\Component\Config\Definition\BooleanNode; + +/** + * A console command for dumping available configuration reference + * + * @author Kevin Bond + */ +class ConfigDumpReferenceCommand extends ContainerDebugCommand +{ + protected $output; + + /** + * @see Command + */ + protected function configure() + { + $this + ->setDefinition(array( + new InputArgument('name', InputArgument::REQUIRED, 'The Bundle or extension alias') + )) + ->setName('config:dump-reference') + ->setDescription('Dumps default configuration for an extension.') + ->setHelp(<<config:dump command dumps the default configuration for an extension/bundle. + +The extension alias or bundle name can be used: + +Example: + + %command.name% framework + +or + + %command.name% FrameworkBundle + +EOF + ) + ; + } + + /** + * @see Command + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $this->output = $output; + $kernel = $this->getContainer()->get('kernel'); + $containerBuilder = $this->getContainerBuilder(); + + $name = $input->getArgument('name'); + + $extension = null; + + if (preg_match('/Bundle$/', $name)) { + // input is bundle name + $extension = $kernel->getBundle($name)->getContainerExtension(); + + if (!$extension) { + throw new \LogicException('No extensions with configuration available for "'.$name.'"'); + } + + $message = 'Default configuration for "'.$name.'"'; + } else { + foreach ($kernel->getBundles() as $bundle) { + $extension = $bundle->getContainerExtension(); + + if ($extension && $extension->getAlias() === $name) { + break; + } + + $extension = null; + } + + if (!$extension) { + throw new \LogicException('No extension with alias "'.$name.'" is enabled'); + } + + $message = 'Default configuration for extension with alias: "'.$name.'"'; + } + + $configuration = $extension->getConfiguration(array(), $containerBuilder); + + if (!$configuration) { + throw new \LogicException('The extension with alias "'.$extension->getAlias(). + '" does not have it\'s getConfiguration() method setup'); + } + + $rootNode = $configuration->getConfigTreeBuilder()->buildTree(); + + $output->writeln($message); + + // root node + $this->outputNode($rootNode); + } + + /** + * Outputs a single config reference line + * + * @param string $text + * @param int $indent + */ + private function outputLine($text, $indent = 0) + { + $indent = strlen($text) + $indent; + + $format = '%'.$indent.'s'; + + $this->output->writeln(sprintf($format, $text)); + } + + private function outputArray(array $array, $depth) + { + $is_indexed = array_values($array) === $array; + + foreach ($array as $key => $value) { + if (is_array($value)) { + $val = ''; + } else { + $val = $value; + } + + if ($is_indexed) { + $this->outputLine('- '.$val, $depth * 4); + } else { + $this->outputLine(sprintf('%-20s %s', $key.':', $val), $depth * 4); + } + + if (is_array($value)) { + $this->outputArray($value, $depth + 1); + } + } + } + + /** + * @param NodeInterface $node + * @param int $depth + */ + private function outputNode(NodeInterface $node, $depth = 0) + { + $comments = array(); + $default = ''; + $defaultArray = null; + $children = null; + $example = $node->getExample(); + + // defaults + if ($node instanceof ArrayNode) { + $children = $node->getChildren(); + + if ($node instanceof PrototypedArrayNode) { + $prototype = $node->getPrototype(); + + if ($prototype instanceof ArrayNode) { + $children = $prototype->getChildren(); + } + + // check for attribute as key + if ($key = $node->getKeyAttribute()) { + $keyNode = new ArrayNode($key, $node); + $keyNode->setInfo('Prototype'); + + // add children + foreach ($children as $childNode) { + $keyNode->addChild($childNode); + } + $children = array($key => $keyNode); + } + } + + if (!$children) { + if ($node->hasDefaultValue() && count($defaultArray = $node->getDefaultValue())) { + $default = ''; + } elseif (!is_array($example)) { + $default = '[]'; + } + } + } else { + $default = '~'; + + if ($node->hasDefaultValue()) { + $default = $node->getDefaultValue(); + + if (true === $default) { + $default = 'true'; + } elseif (false === $default) { + $default = 'false'; + } elseif (null === $default) { + $default = '~'; + } + } + } + + // required? + if ($node->isRequired()) { + $comments[] = 'Required'; + } + + // example + if ($example && !is_array($example)) { + $comments[] = 'Example: '.$example; + } + + $default = (string) $default != '' ? ' '.$default : ''; + $comments = count($comments) ? '# '.implode(', ', $comments) : ''; + + $text = sprintf('%-20s %s %s', $node->getName().':', $default, $comments); + + if ($info = $node->getInfo()) { + $this->outputLine(''); + $this->outputLine('# '.$info, $depth * 4); + } + + $this->outputLine($text, $depth * 4); + + // output defaults + if ($defaultArray) { + $this->outputLine(''); + + $message = count($defaultArray) > 1 ? 'Defaults' : 'Default'; + + $this->outputLine('# '.$message.':', $depth * 4 + 4); + + $this->outputArray($defaultArray, $depth + 1); + } + + if (is_array($example)) { + $this->outputLine(''); + + $message = count($example) > 1 ? 'Examples' : 'Example'; + + $this->outputLine('# '.$message.':', $depth * 4 + 4); + + $this->outputArray($example, $depth + 1); + } + + if ($children) { + foreach ($children as $childNode) { + $this->outputNode($childNode, $depth + 1); + } + } + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php index 305832545f..48d501526e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php @@ -183,7 +183,7 @@ EOF * * @return ContainerBuilder */ - private function getContainerBuilder() + protected function getContainerBuilder() { if (!$this->getApplication()->getKernel()->isDebug()) { throw new \LogicException(sprintf('Debug information about the container is only available in debug mode.')); diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 5762fb4c33..5195ff1c2f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -46,7 +46,7 @@ class Configuration implements ConfigurationInterface $rootNode ->children() - ->scalarNode('charset')->end() + ->scalarNode('charset')->setInfo('general configuration')->end() ->scalarNode('trust_proxy_headers')->defaultFalse()->end() ->scalarNode('secret')->isRequired()->end() ->scalarNode('ide')->defaultNull()->end() @@ -73,6 +73,7 @@ class Configuration implements ConfigurationInterface $rootNode ->children() ->arrayNode('form') + ->setInfo('form configuration') ->canBeUnset() ->treatNullLike(array('enabled' => true)) ->treatTrueLike(array('enabled' => true)) @@ -98,6 +99,7 @@ class Configuration implements ConfigurationInterface $rootNode ->children() ->arrayNode('esi') + ->setInfo('esi configuration') ->canBeUnset() ->treatNullLike(array('enabled' => true)) ->treatTrueLike(array('enabled' => true)) @@ -114,6 +116,7 @@ class Configuration implements ConfigurationInterface $rootNode ->children() ->arrayNode('profiler') + ->setInfo('profiler configuration') ->canBeUnset() ->children() ->booleanNode('only_exceptions')->defaultFalse()->end() @@ -142,6 +145,7 @@ class Configuration implements ConfigurationInterface $rootNode ->children() ->arrayNode('router') + ->setInfo('router configuration') ->canBeUnset() ->children() ->scalarNode('resource')->isRequired()->end() @@ -159,6 +163,7 @@ class Configuration implements ConfigurationInterface $rootNode ->children() ->arrayNode('session') + ->setInfo('session configuration') ->canBeUnset() ->children() ->booleanNode('auto_start')->defaultFalse()->end() @@ -201,6 +206,7 @@ class Configuration implements ConfigurationInterface $rootNode ->children() ->arrayNode('templating') + ->setInfo('templating configuration') ->canBeUnset() ->children() ->scalarNode('assets_version')->defaultValue(null)->end() @@ -251,6 +257,7 @@ class Configuration implements ConfigurationInterface ->fixXmlConfig('engine') ->children() ->arrayNode('engines') + ->setExample(array('twig')) ->isRequired() ->requiresAtLeastOneElement() ->beforeNormalization() @@ -314,6 +321,7 @@ class Configuration implements ConfigurationInterface $rootNode ->children() ->arrayNode('translator') + ->setInfo('translator configuration') ->canBeUnset() ->treatNullLike(array('enabled' => true)) ->treatTrueLike(array('enabled' => true)) @@ -331,6 +339,7 @@ class Configuration implements ConfigurationInterface $rootNode ->children() ->arrayNode('validation') + ->setInfo('validation configuration') ->canBeUnset() ->treatNullLike(array('enabled' => true)) ->treatTrueLike(array('enabled' => true)) @@ -349,6 +358,7 @@ class Configuration implements ConfigurationInterface $rootNode ->children() ->arrayNode('annotations') + ->setInfo('annotation configuration') ->addDefaultsIfNotSet() ->children() ->scalarNode('cache')->defaultValue('file')->end() diff --git a/src/Symfony/Bundle/MonologBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/MonologBundle/DependencyInjection/Configuration.php index 633fac9203..8462b23a75 100644 --- a/src/Symfony/Bundle/MonologBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/MonologBundle/DependencyInjection/Configuration.php @@ -107,6 +107,26 @@ class Configuration implements ConfigurationInterface ->ifTrue(function($v) { return isset($v['debug']); }) ->thenInvalid('The "debug" name cannot be used as it is reserved for the handler of the profiler') ->end() + ->setExample(array( + 'syslog' => array( + 'type' => 'stream', + 'path' => '/var/log/symfony.log', + 'level' => 'ERROR', + 'bubble' => 'false', + 'formatter' => 'my_formatter', + 'processors' => array('some_callable') + ), + 'main' => array( + 'type' => 'fingerscrossed', + 'action_level' => 'WARNING', + 'buffer_size' => 30, + 'handler' => 'custom', + ), + 'custom' => array( + 'type' => 'service', + 'id' => 'my_handler' + ) + )) ->end() ->end() ; diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php index c1f99ac56a..70065d8e17 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php @@ -57,8 +57,8 @@ class MainConfiguration implements ConfigurationInterface $rootNode ->children() - ->scalarNode('access_denied_url')->defaultNull()->end() - ->scalarNode('session_fixation_strategy')->cannotBeEmpty()->defaultValue('migrate')->end() + ->scalarNode('access_denied_url')->defaultNull()->setExample('/foo/error403')->end() + ->scalarNode('session_fixation_strategy')->cannotBeEmpty()->setInfo('strategy can be: none, migrate, invalidate')->defaultValue('migrate')->end() ->booleanNode('hide_user_not_found')->defaultTrue()->end() ->booleanNode('always_authenticate_before_granting')->defaultFalse()->end() ->booleanNode('erase_credentials')->defaultTrue()->end() @@ -89,7 +89,7 @@ class MainConfiguration implements ConfigurationInterface ->children() ->arrayNode('acl') ->children() - ->scalarNode('connection')->end() + ->scalarNode('connection')->setInfo('any name configured in doctrine.dbal section')->end() ->arrayNode('cache') ->addDefaultsIfNotSet() ->children() @@ -290,6 +290,16 @@ class MainConfiguration implements ConfigurationInterface ->fixXmlConfig('provider') ->children() ->arrayNode('providers') + ->setExample(array( + 'memory' => array( + 'name' => 'memory', + 'users' => array( + 'foo' => array('password' => 'foo', 'roles' => 'ROLE_USER'), + 'bar' => array('password' => 'bar', 'roles' => '[ROLE_USER, ROLE_ADMIN]') + ) + ), + 'entity' => array('entity' => array('class' => 'SecurityBundle:User', 'property' => 'username')) + )) ->disallowNewKeysInSubsequentConfigs() ->isRequired() ->requiresAtLeastOneElement() @@ -340,6 +350,14 @@ class MainConfiguration implements ConfigurationInterface ->fixXmlConfig('encoder') ->children() ->arrayNode('encoders') + ->setExample(array( + 'Acme\DemoBundle\Entity\User1' => 'sha512', + 'Acme\DemoBundle\Entity\User2' => array( + 'algorithm' => 'sha512', + 'encode_as_base64' => 'true', + 'iterations'=> 5000 + ) + )) ->requiresAtLeastOneElement() ->useAttributeAsKey('class') ->prototype('array') diff --git a/src/Symfony/Bundle/TwigBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/TwigBundle/DependencyInjection/Configuration.php index 160dc671c7..74d52bdf98 100644 --- a/src/Symfony/Bundle/TwigBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/TwigBundle/DependencyInjection/Configuration.php @@ -56,6 +56,7 @@ class Configuration implements ConfigurationInterface ->arrayNode('resources') ->addDefaultsIfNotSet() ->defaultValue(array('form_div_layout.html.twig')) + ->setExample(array('MyBundle::form.html.twig')) ->validate() ->ifTrue(function($v) { return !in_array('form_div_layout.html.twig', $v); }) ->then(function($v){ @@ -77,6 +78,7 @@ class Configuration implements ConfigurationInterface ->children() ->arrayNode('globals') ->useAttributeAsKey('key') + ->setExample(array('foo' => '"@bar"', 'pi' => 3.14)) ->prototype('array') ->beforeNormalization() ->ifTrue(function($v){ return is_string($v) && 0 === strpos($v, '@'); }) @@ -116,7 +118,7 @@ class Configuration implements ConfigurationInterface $rootNode ->children() ->scalarNode('autoescape')->end() - ->scalarNode('base_template_class')->end() + ->scalarNode('base_template_class')->setExample('Twig_Template')->end() ->scalarNode('cache')->defaultValue('%kernel.cache_dir%/twig')->end() ->scalarNode('charset')->defaultValue('%kernel.charset%')->end() ->scalarNode('debug')->defaultValue('%kernel.debug%')->end()