10000 merged branch kbond/config_dump_command (PR #3187) · Olajide/symfony@79a957b · GitHub
[go: up one dir, main page]

Skip to content

Commit 79a957b

Browse files
committed
merged branch kbond/config_dump_command (PR symfony#3187)
Commits ------- 4847d3a renamed command e97af0b code fixes df94282 [FrameworkBundle] removed unnecessary DebugCommand fa32885 [SecurityBundle] added configuration info 2f8ad93 [MonologBundle] added configuration info 9757958 [FrameworkBundle] added configuration info 58939f1 [TwigBundle] added configuration docs 8dc40e4 [FrameworkBundle] added config:dump console command Discussion ---------- Config dump command Bug fix: no Feature addition: yes Backwards compatibility break: no Symfony2 tests pass: yes Fixes the following tickets: symfony#1663 Todo: add more config info/examples [![Build Status](https://secure.travis-ci.org/kbond/symfony.png?branch=config_dump_command)](http://travis-ci.org/kbond/symfony) This is a config dump command based on the additions of PR symfony#1099. This was initially part of that PR and there is some discussion there about it (symfony#1099) ### Usage: 1. dump by root node: ``app/console config:dump framework`` 2. dump by bundle name: ``app/console config:dump FrameworkBundle`` A few issues/notes: * Only dumps to yaml * Only 1 configuration per bundle (this was brought by @stof here: symfony#1099 (comment)) * Works out of the box for most bundles but not ones that use a non-standard ``Configuration`` class (such as the assetic bundle). In this case ``Extension::getConfiguration()`` must be configurated. I have used it to create some (most) of the config reference docs. It works fine but I find it somewhat crude, any suggestions to improve it would be appreciated. --------------------------------------------------------------------------- by kbond at 2012-01-24T21:00:43Z Few more issues: 1. Should I abstract the logic to a "normalizer" class that converts the Configuration class into a manageable array? I struggle with this idea because isn't that what ``TreeBuilder`` basically is? 2. @stof made a good point that ``config:dump`` doesn't really describe what this does. Would dumping your config be useful? Perhaps ``config:dump framework`` dumps the config for your project while ``config:dump --ref framework`` dumps the default reference? --------------------------------------------------------------------------- by stof at 2012-01-24T21:18:15Z @kbond you cannot really dump the config. Part of it does not go through these extensions at all. And it does not make much sense anyway IMO. the command as is does the right job IMO (i.e. dumping a reference for the extension). But its name should be improved --------------------------------------------------------------------------- by kbond at 2012-01-24T21:20:51Z ``config:reference`` perhaps? --------------------------------------------------------------------------- by fabpot at 2012-02-02T10:05:19Z This command is about displaying the default configuration for a given bundle. So, what about `config:dump-reference`? As I understand, the command name is the last element to figure out before merging, right? --------------------------------------------------------------------------- by stof at 2012-02-02T10:19:49Z @fabpot indeed. --------------------------------------------------------------------------- by stof at 2012-02-02T10:34:16Z and +1 for ``config:dump-reference`` --------------------------------------------------------------------------- by Tobion at 2012-02-02T12:08:03Z why not use the words you chose yourself: `config:dump-default` I think it's more explicit.
2 parents 5251177 + 4847d3a commit 79a957b

File tree

6 files changed

+317
-6
lines changed

6 files changed

+317
-6
lines changed
Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\FrameworkBundle\Command;
13+
14+
use Symfony\Component\Console\Input\InputArgument;
15+
use Symfony\Component\Console\Input\InputInterface;
16+
use Symfony\Component\Console\Output\OutputInterface;
17+
use Symfony\Component\Config\Definition\NodeInterface;
18+
use Symfony\Component\Config\Definition\ArrayNode;
19+
use Symfony\Component\Config\Definition\PrototypedArrayNode;
20+
use Symfony\Component\Config\Definition\BooleanNode;
21+
22+
/**
23+
* A console command for dumping available configuration reference
24+
*
25+
* @author Kevin Bond <kevinbond@gmail.com>
26+
*/
27+
class ConfigDumpReferenceCommand extends ContainerDebugCommand
28+
{
29+
protected $output;
30+
31+
/**
32+
* @see Command
33+
*/
34+
protected function configure()
35+
{
36+
$this
37+
->setDefinition(array(
38+
new InputArgument('name' 1E79 , InputArgument::REQUIRED, 'The Bundle or extension alias')
39+
))
40+
->setName('config:dump-reference')
41+
->setDescription('Dumps default configuration for an extension.')
42+
->setHelp(<<<EOF
43+
The <info>config:dump</info> command dumps the default configuration for an extension/bundle.
44+
45+
The extension alias or bundle name can be used:
46+
47+
Example:
48+
49+
<info>%command.name% framework</info>
50+
51+
or
52+
53+
<info>%command.name% FrameworkBundle</info>
54+
55+
EOF
56+
)
57+
;
58+
}
59+
60+
/**
61+
* @see Command
62+
*/
63+
protected function execute(InputInterface $input, OutputInterface $output)
64+
{
65+
$this->output = $output;
66+
$kernel = $this->getContainer()->get('kernel');
67+
$containerBuilder = $this->getContainerBuilder();
68+
69+
$name = $input->getArgument('name');
70+
71+
$extension = null;
72+
73+
if (preg_match('/Bundle$/', $name)) {
74+
// input is bundle name
75+
$extension = $kernel->getBundle($name)->getContainerExtension();
76+
77+
if (!$extension) {
78+
throw new \LogicException('No extensions with configuration available for "'.$name.'"');
79+
}
80+
81+
$message = 'Default configuration for "'.$name.'"';
82+
} else {
83+
foreach ($kernel->getBundles() as $bundle) {
84+
$extension = $bundle->getContainerExtension();
85+
86+
if ($extension && $extension->getAlias() === $name) {
87+
break;
88+
}
89+
90+
$extension = null;
91+
}
92+
93+
if (!$extension) {
94+
throw new \LogicException('No extension with alias "'.$name.'" is enabled');
95+
}
96+
97+
$message = 'Default configuration for extension with alias: "'.$name.'"';
98+
}
99+
100+
$configuration = $extension->getConfiguration(array(), $containerBuilder);
101+
102+
if (!$configuration) {
103+
throw new \LogicException('The extension with alias "'.$extension->getAlias().
104+
'" does not have it\'s getConfiguration() method setup');
105+
}
106+
107+
$rootNode = $configuration->getConfigTreeBuilder()->buildTree();
108+
109+
$output->writeln($message);
110+
111+
// root node
112+
$this->outputNode($rootNode);
113+
}
114+
115+
/**
116+
* Outputs a single config reference line
117+
*
118+
* @param string $text
119+
* @param int $indent
120+
*/
121+
private function outputLine($text, $indent = 0)
122+
{
123+
$indent = strlen($text) + $indent;
124+
125+
$format = '%'.$indent.'s';
126+
127+
$this->output->writeln(sprintf($format, $text));
128+
}
129+
130+
private function outputArray(array $array, $depth)
131+
{
132+
$is_indexed = array_values($array) === $array;
133+
134+
foreach ($array as $key => $value) {
135+
if (is_array($value)) {
136+
$val = '';
137+
} else {
138+
$val = $value;
139+
}
140+
141+
if ($is_indexed) {
142+
$this->outputLine('- '.$val, $depth * 4);
143+
} else {
144+
$this->outputLine(sprintf('%-20s %s', $key.':', $val), $depth * 4);
145+
}
146+
147+
if (is_array($value)) {
148+
$this->outputArray($value, $depth + 1);
149+
}
150+
}
151+
}
152+
153+
/**
154+
* @param NodeInterface $node
155+
* @param int $depth
156+
*/
157+
private function outputNode(NodeInterface $node, $depth = 0)
158+
{
159+
$comments = array();
160+
$default = '';
161+
$defaultArray = null;
162+
$children = null;
163+
$example = $node->getExample();
164+
165+
// defaults
166+
if ($node instanceof ArrayNode) {
167+
$children = $node->getChildren();
168+
169+
if ($node instanceof PrototypedArrayNode) {
170+
$prototype = $node->getPrototype();
171+
172+
if ($prototype instanceof ArrayNode) {
173+
$children = $prototype->getChildren();
174+
}
175+
176+
// check for attribute as key
177+
if ($key = $node->getKeyAttribute()) {
178+
$keyNode = new ArrayNode($key, $node);
179+
$keyNode->setInfo('Prototype');
180+
181+
// add children
182+
foreach ($children as $childNode) {
183+
$keyNode->addChild($childNode);
184+
}
185+
$children = array($key => $keyNode);
186+
}
187+
}
188+
189+
if (!$children) {
190+
if ($node->hasDefaultValue() && count($defaultArray = $node->getDefaultValue())) {
191+
$default = '';
192+
} elseif (!is_array($example)) {
193+
$default = '[]';
194+
}
195+
}
196+
} else {
197+
$default = '~';
198+
199+
if ($node->hasDefaultValue()) {
200+
$default = $node->getDefaultValue();
201+
202+
if (true === $default) {
203+
$default = 'true';
204+
} elseif (false === $default) {
205+
$default = 'false';
206+
} elseif (null === $default) {
207+
$default = '~';
208+
}
209+
}
210+
}
211+
212+
// required?
213+
if ($node->isRequired()) {
214+
$comments[] = 'Required';
215+
}
216+
217+
// example
218+
if ($example && !is_array($example)) {
219+
$comments[] = 'Example: '.$example;
220+
}
221+
222+
$default = (string) $default != '' ? ' '.$default : '';
223+
$comments = count($comments) ? '# '.implode(', ', $comments) : '';
224+
225+
$text = sprintf('%-20s %s %s', $node->getName().':', $default, $comments);
226+
227+
if ($info = $node->getInfo()) {
228+
$this->outputLine('');
229+
$this->outputLine('# '.$info, $depth * 4);
230+
}
231+
232+
$this->outputLine($text, $depth * 4);
233+
234+
// output defaults
235+
if ($defaultArray) {
236+
$this->outputLine('');
237+
238+
$message = count($defaultArray) > 1 ? 'Defaults' : 'Default';
239+
240+
$this->outputLine('# '.$message.':', $depth * 4 + 4);
241+
242+
$this->outputArray($defaultArray, $depth + 1);
243+
}
244+
245+
if (is_array($example)) {
246+
$this->outputLine('');
247+
248+
$message = count($example) > 1 ? 'Examples' : 'Example';
249+
250+
$this->outputLine('# '.$message.':', $depth * 4 + 4);
251+
252+
$this->outputArray($example, $depth + 1);
253+
}
254+
255+
if ($children) {
256+
foreach ($children as $childNode) {
257+
$this->outputNode($childNode, $depth + 1);
258+
}
259+
}
260+
}
261+
}

src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ protected function outputService(OutputInterface $output, $serviceId)
183183
*
184184
* @return ContainerBuilder
185185
*/
186-
private function getContainerBuilder()
186+
protected function getContainerBuilder()
187187
{
188188
if (!$this->getApplication()->getKernel()->isDebug()) {
189189
throw new \LogicException(sprintf('Debug information about the container is only available in debug mode.'));

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public function getConfigTreeBuilder()
4646

4747
$rootNode
4848
->children()
49-
->scalarNode('charset')->end()
49+
->scalarNode('charset')->setInfo('general configuration')->end()
5050
->scalarNode('trust_proxy_headers')->defaultFalse()->end()
5151
->scalarNode('secret')->isRequired()->end()
5252
->scalarNode('ide')->defaultNull()->end()
@@ -73,6 +73,7 @@ private function addFormSection(ArrayNodeDefinition $rootNode)
7373
$rootNode
7474
->children()
7575
->arrayNode('form')
76+
->setInfo('form configuration')
7677
->canBeUnset()
7778
->treatNullLike(array('enabled' => true))
7879
->treatTrueLike(array('enabled' => true))
@@ -98,6 +99,7 @@ private function addEsiSection(ArrayNodeDefinition $rootNode)
9899
$rootNode
99100
->children()
100101
->arrayNode('esi')
102+
->setInfo('esi configuration')
101103
->canBeUnset()
102104
->treatNullLike(array('enabled' => true))
103105
->treatTrueLike(array('enabled' => true))
@@ -114,6 +116,7 @@ private function addProfilerSection(ArrayNodeDefinition $rootNode)
114116
$rootNode
115117
->children()
116118
->arrayNode('profiler')
119+
->setInfo('profiler configuration')
117120
->canBeUnset()
118121
->children()
119122
->booleanNode('only_exceptions')->defaultFalse()->end()
@@ -142,6 +145,7 @@ private function addRouterSection(ArrayNodeDefinition $rootNode)
142145
$rootNode
143146
->children()
144147
->arrayNode('router')
148+
->setInfo('router configuration')
145149
->canBeUnset()
146150
->children()
147151
->scalarNode('resource')->isRequired()->end()
@@ -159,6 +163,7 @@ private function addSessionSection(ArrayNodeDefinition $rootNode)
159163
$rootNode
160164
->children()
161165
->arrayNode('session')
166+
->setInfo('session configuration')
162167
->canBeUnset()
163168
->children()
164169
->booleanNode('auto_start')->defaultFalse()->end()
@@ -201,6 +206,7 @@ private function addTemplatingSection(ArrayNodeDefinition $rootNode)
201206
$rootNode
202207
->children()
203208
->arrayNode('templating')
209+
->setInfo('templating configuration')
204210
->canBeUnset()
205211
->children()
206212
->scalarNode('assets_version')->defaultValue(null)->end()
@@ -251,6 +257,7 @@ private function addTemplatingSection(ArrayNodeDefinition $rootNode)
251257
->fixXmlConfig('engine')
252258
->children()
253259
->arrayNode('engines')
260+
->setExample(array('twig'))
254261
->isRequired()
255262
->requiresAtLeastOneElement()
256263
->beforeNormalization()
@@ -314,6 +321,7 @@ private function addTranslatorSection(ArrayNodeDefinition $rootNode)
314321
$rootNode
315322
->children()
316323
->arrayNode('translator')
324+
->setInfo('translator configuration')
317325
->canBeUnset()
318326
->treatNullLike(array('enabled' => true))
319327
->treatTrueLike(array('enabled' => true))
@@ -331,6 +339,7 @@ private function addValidationSection(ArrayNodeDefinition $rootNode)
331339
$rootNode
332340
->children()
333341
->arrayNode('validation')
342+
->setInfo('validation configuration')
334343
->canBeUnset()
335344
->treatNullLike(array('enabled' => true))
336345
->treatTrueLike(array('enabled' => true))
@@ -349,6 +358,7 @@ private function addAnnotationsSection(ArrayNodeDefinition $rootNode)
349358
$rootNode
350359
->children()
351360
->arrayNode('annotations')
361+
->setInfo('annotation configuration')
352362
->addDefaultsIfNotSet()
353363
->children()
354364
->scalarNode('cache')->defaultValue('file')->end()

src/Symfony/Bundle/MonologBundle/DependencyInjection/Configuration.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,26 @@ public function getConfigTreeBuilder()
107107
->ifTrue(function($v) { return isset($v['debug']); })
108108
->thenInvalid('The "debug" name cannot be used as it is reserved for the handler of the profiler')
109109
->end()
110+
->setExample(array(
111+
'syslog' => array(
112+
'type' => 'stream',
113+
'path' => '/var/log/symfony.log',
114+
'level' => 'ERROR',
115+
'bubble' => 'false',
116+
'formatter' => 'my_formatter',
117+
'processors' => array('some_callable')
118+
),
119+
'main' => array(
120+
'type' => 'fingerscrossed',
121+
'action_level' => 'WARNING',
122+
'buffer_size' => 30,
123+
'handler' => 'custom',
124+
),
125+
'custom' => array(
126+
'type' => 'service',
127+
'id' => 'my_handler'
128+
)
129+
))
110130
->end()
111131
->end()
112132
;

0 commit comments

Comments
 (0)
0