Skip to content

Commit 099b9de

Browse files
jmikolafabpot
authored andcommitted
[FrameworkBundle] Integrate Configuration\Builder class for config merging and normalization
This fixes some BC problems introduced in f9138d3. Some top-level can now be simply enabled by providing true/null in PHP/YAML. Additionally, the Configuration\Builder allows options to be unset by providing "false" (helpful for overriding activation in a previous config file). All options supporting these behaviors can be found in the Configuration.php file (look for canBeUnset() and treatNull/TrueLike()). Major changes: * Removed "enabled" option for profiler config. Profiler is now enabled if its config is true, null or a map. * Restore original config structure for validation namespaces. In PHP/YAML, namespaces are defined under annotations as an alternative to false (disabled) and true/null (enabled). For XML, annotation remains a boolean attribute for validation and a one or more optional namespace tags may appear within <app:validation />. During config normalization, namespace tags under validation will be moved to annotations to conform to the PHP/YAML structure (this occurs transparently to the user). * Restore behavior for router/templating config sections being optional (as shown in changes to session/validation test fixtures). If either top-level section is unset in the configuration, neither feature will be enabled and the user will no longer receive exceptions due to missing a resource option (router) or engines (templating). Resource/engines will still be properly required if the respective feature is enabled. * Remove unused router type option from XML config XSD. Type is only relevant for import statements, so this option is likely useless. Additional small changes: * Added isset()'s, since config options may be unset * Wrap registerXxxConfiguration() calls in isset() checks * Load translation.xml in configLoad(), since it's always required * Default cache_warmer value (!kernel.debug) is determined via Configuration class Things to be fixed: * Configuration\Builder doesn't seem to respect isRequired() and requiresAtLeastOneElement() (or I haven't set it properly); this should replace the need for FrameworkExtension to throw exceptions for bad router/templating configs * The config nodes for session options don't have the "pdo." prefix, as dots are not allowed in node names. To preserve BC for now, the "pdo." prefix is still allowed (and mandated by XSD) in configuration files. In the future, we may just want to do away with the "pdo." prefix. * Translator has an "enabled" option. If there's no use case for setting "fallback" independently (when "enabled" is false), perhaps "enabled" should be removed entirely and translator should function like profiler currently does. * Profiler matcher merging might need to be adjusted so multiple configs simply overwrite matcher instead of merging its array keys.
1 parent 2b256a0 commit 099b9de

File tree

10 files changed

+339
-308
lines changed

10 files changed

+339
-308
lines changed
Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
<?php
2+
3+
namespace Symfony\Bundle\FrameworkBundle\DependencyInjection;
4+
5+
use Symfony\Component\DependencyInjection\Configuration\Builder\NodeBuilder;
6+
use Symfony\Component\DependencyInjection\Configuration\Builder\TreeBuilder;
7+
8+
/**
9+
* FrameworkExtension configuration structure.
10+
*
11+
* @author Jeremy Mikola <jmikola@gmail.com>
12+
*/
13+
class Configuration
14+
{
15+
/**
16+
* Generates the configuration tree.
17+
*
18+
* @param boolean $kernelDebug The kernel.debug DIC parameter
19+
* @return \Symfony\Component\DependencyInjection\Configuration\NodeInterface
20+
*/
21+
public function getConfigTree($kernelDebug)
22+
{
23+
$treeBuilder = new TreeBuilder();
24+
$rootNode = $treeBuilder->root('app:config', 'array');
25+
26+
$rootNode
27+
->scalarNode('cache_warmer')->defaultValue(!$kernelDebug)->end()
28+
->scalarNode('charset')->end()
29+
->scalarNode('document_root')->end()
30+
->scalarNode('error_handler')->end()
31+
->scalarNode('ide')->end()
32+
->booleanNode('test')->end()
33+
;
34+
35+
$this->addCsrfProtectionSection($rootNode);
36+
$this->addEsiSection($rootNode);
37+
$this->addProfilerSection($rootNode);
38+
$this->addRouterSection($rootNode);
39+
$this->addSessionSection($rootNode);
40+
$this->addTemplatingSection($rootNode);
41+
$this->addTranslatorSection($rootNode);
42+
$this->addValidationSection($rootNode);
43+
44+
return $treeBuilder->buildTree();
45+
}
46+
47+
private function addCsrfProtectionSection(NodeBuilder $rootNode)
48+
{
49+
$rootNode
50+
->arrayNode('csrf_protection')
51+
->canBeUnset()
52+
->treatNullLike(array('enabled' => true))
53+
->treatTrueLike(array('enabled' => true))
54+
->booleanNode('enabled')->end()
55+
->scalarNode('field_name')->end()
56+
->scalarNode('secret')->end()
57+
->end()
58+
;
59+
}
60+
61+
private function addEsiSection(NodeBuilder $rootNode)
62+
{
63+
$rootNode
64+
->arrayNode('esi')
65+
->canBeUnset()
66+
->treatNullLike(array('enabled' => true))
67+
->treatTrueLike(array('enabled' => true))
68+
->booleanNode('enabled')->end()
69+
->end()
70+
;
71+
}
72+
73+
private function addProfilerSection(NodeBuilder $rootNode)
74+
{
75+
$rootNode
76+
->arrayNode('profiler')
77+
->canBeUnset()
78+
->treatNullLike(array())
79+
->treatTrueLike(array())
80+
->booleanNode('only_exceptions')->end()
81+
->arrayNode('matcher')
82+
->canBeUnset()
83+
->scalarNode('ip')->end()
84+
->scalarNode('path')->end()
85+
->scalarNode('service')->end()
86+
->end()
87+
->end()
88+
;
89+
}
90+
91+
private function addRouterSection(NodeBuilder $rootNode)
92+
{
93+
$rootNode
94+
->arrayNode('router')
95+
->canBeUnset()
96+
->scalarNode('cache_warmer')->end()
97+
->scalarNode('resource')->isRequired()->end()
98+
->end()
99+
;
100+
}
101+
102+
private function addSessionSection(NodeBuilder $rootNode)
103+
{
104+
$rootNode
105+
->arrayNode('session')
106+
->canBeUnset()
107+
->treatNullLike(array())
108+
->treatTrueLike(array())
109+
// Strip "pdo." prefix from option keys, since dots cannot appear in node names
110+
->beforeNormalization()
111+
->ifArray()
112+
->then(function($v){
113+
foreach ($v as $key => $value) {
114+
if (0 === strncmp('pdo.', $key, 4)) {
115+
$v[substr($key, 4)] = $value;
116+
unset($v[$key]);
117+
}
118+
}
119+
return $v;
120+
})
121+
->end()
122+
->booleanNode('auto_start')->end()
123+
->scalarNode('class')->end()
124+
->scalarNode('default_locale')->end()
125+
->scalarNode('storage_id')->defaultValue('native')->end()
126+
// NativeSessionStorage options
127+
->scalarNode('name')->end()
128+
->scalarNode('lifetime')->end()
129+
->scalarNode('path')->end()
130+
->scalarNode('domain')->end()
131+
->booleanNode('secure')->end()
132+
->booleanNode('httponly')->end()
133+
// PdoSessionStorage options
134+
->scalarNode('db_table')->end()
135+
->scalarNode('db_id_col')->end()
136+
->scalarNode('db_data_col')->end()
137+
->scalarNode('db_time_col')->end()
138+
->end()
139+
;
140+
}
141+
142+
private function addTemplatingSection(NodeBuilder $rootNode)
143+
{
144+
$rootNode
145+
->arrayNode('templating')
146+
->canBeUnset()
147+
->scalarNode('assets_version')->end()
148+
->scalarNode('assets_base_urls')->end()
149+
->scalarNode('cache')->end()
150+
->scalarNode('cache_warmer')->end()
151+
->fixXmlConfig('engine')
152+
->arrayNode('engines')
153+
->requiresAtLeastOneElement()
154+
->beforeNormalization()
155+
->ifTrue(function($v){ return !is_array($v); })
156+
->then(function($v){ return array($v); })
157+
->end()
158+
->prototype('scalar')
159+
->beforeNormalization()
160+
->ifTrue(function($v) { return is_array($v) && isset($v['id']); })
161+
->then(function($v){ return $v['id']; })
162+
->end()
163+
->end()
164+
->end()
165+
->fixXmlConfig('loader')
166+
->arrayNode('loaders')
167+
->beforeNormalization()
168+
->ifTrue(function($v){ return !is_array($v); })
169+
->then(function($v){ return array($v); })
170+
->end()
171+
->prototype('scalar')->end()
172+
->end()
173+
->end()
174+
;
175+
}
176+
177+
private function addTranslatorSection(NodeBuilder $rootNode)
178+
{
179+
$rootNode
180+
->arrayNode('translator')
181+
->canBeUnset()
182+
->booleanNode('enabled')->defaultTrue()->end()
183+
->scalarNode('fallback')->end()
184+
->end()
185+
;
186+
}
187+
188+
private function addValidationSection(NodeBuilder $rootNode)
189+
{
190+
$rootNode
191+
->arrayNode('validation')
192+
->canBeUnset()
193+
// For XML, namespace is a child of validation, so it must be moved under annotations
194+
->beforeNormalization()
195+
->ifTrue(function($v) { return is_array($v) && !empty($v['annotations']) && !empty($v['namespace']); })
196+
->then(function($v){
197+
$v['annotations'] = array('namespace' => $v['namespace']);
198+
return $v;
199+
})
200+
->end()
201+
->booleanNode('enabled')->end()
202+
->arrayNode('annotations')
203+
->canBeUnset()
204+
->treatNullLike(array())
205+
->treatTrueLike(array())
206+
->fixXmlConfig('namespace')
207+
->arrayNode('namespaces')
208+
->containsNameValuePairsWithKeyAttribute('prefix')
209+
->prototype('scalar')
210+
->beforeNormalization()
211+
->ifTrue(function($v) { return is_array($v) && isset($v['namespace']); })
212+
->then(function($v){ return $v['namespace']; })
213+
->end()
214+
->end()
215+
->end()
216+
->end()
217+
->end()
218+
;
219+
}
220+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy