@@ -212,6 +212,168 @@ For all nodes:
212
212
``cannotBeOverwritten() ``
213
213
don’t let other configuration arrays overwrite an existing value for this node
214
214
215
+ Appending sections
216
+ ------------------
217
+
218
+ If you have a complex configuration to validate then the tree can grow to
219
+ be large and you may want to split it up into sections. You can do this by
220
+ making a section a separate node and then appending it into the main tree
221
+ with ``append() ``::
222
+
223
+ public function getConfigTreeBuilder()
224
+ {
225
+ $treeBuilder = new TreeBuilder();
226
+ $rootNode = $treeBuilder->root('database');
227
+
228
+ $rootNode
229
+ ->arrayNode('connection')
230
+ ->children()
231
+ ->scalarNode('driver')
232
+ ->isRequired()
233
+ ->cannotBeEmpty()
234
+ ->end()
235
+ ->scalarNode('host')
236
+ ->defaultValue('localhost')
237
+ ->end()
238
+ ->scalarNode('username')->end()
239
+ ->scalarNode('password')->end()
240
+ ->booleanNode('memory')
241
+ ->defaultFalse()
242
+ ->end()
243
+ ->end()
244
+ ->append($this->addParametersNode())
245
+ ->end()
246
+ ;
247
+
248
+ return $treeBuilder;
249
+ }
250
+
251
+ public function addParametersNode()
252
+ {
253
+ $builder = new TreeBuilder();
254
+ $node = $builder->root('parameters');
255
+
256
+ $node
257
+ ->isRequired()
258
+ ->requiresAtLeastOneElement()
259
+ ->useAttributeAsKey('name')
260
+ ->prototype('array')
261
+ ->children()
262
+ ->scalarNode('name')->isRequired()->end()
263
+ ->scalarNode('value')->isRequired()->end()
264
+ ->end()
265
+ ->end()
266
+ ;
267
+
268
+ return $node;
269
+ }
270
+
271
+ This is also useful to help you avoid repeating yourself if you have sections
272
+ of the config that are repeated in different places.
273
+
274
+ Normalization
275
+ -------------
276
+
277
+ When the config files are processed they are first normalized, they are then
278
+ merged and then the tree is used to validate the resulting array. The normalization
279
+ is to remove some of the differences that result from different configuration formats,
280
+ mainly the differences between Yaml and XML.
281
+
282
+ The separator used in keys is typically ``_ `` in Yaml and ``- `` in XML. For
283
+ example, ``auto_connect `` in Yaml and ``auto-connect ``. The normalization would
284
+ make both of these ``auto_connect ``.
285
+
286
+ Another difference between Yaml and XML is in the way arrays of values may
287
+ be represented. In Yaml you may have:
288
+
289
+ .. code-block :: yaml
290
+
291
+ twig :
292
+ extensions : ['twig.extension.foo', 'twig.extension.bar']
293
+
294
+ and in XML:
295
+
296
+ .. code-block :: xml
297
+
298
+ <twig : config >
299
+ <twig : extension >twig.extension.foo</twig : extension >
300
+ <twig : extension >twig.extension.bar</twig : extension >
301
+ </twig : config >
302
+
303
+ This difference can be removed in normalization by pluralizing the key used
304
+ in XML. You can specify that you want a key to be pluralized in this way with
305
+ ``fixXmlConfig() ``::
306
+
307
+ $rootNode
308
+ ->fixXmlConfig('extension')
309
+ ->children()
310
+ ->arrayNode('extensions')
311
+ ->prototype('scalar')->end()
312
+ ->end()
313
+ ->end()
314
+ ;
315
+
316
+ If it is an irregular pluralization you can specify the plural to use as
317
+ a second argument::
318
+
319
+ $rootNode
320
+ ->fixXmlConfig('child', 'children')
321
+ ->children()
322
+ ->arrayNode('children')
323
+ ->end()
324
+ ;
325
+
326
+ As well as fixing this it ensures that single xml elements are still turned into an array.
327
+ So you may have:
328
+
329
+ .. code-block :: xml
330
+
331
+ <connection >default</connection >
332
+ <connection >extra</connection >
333
+
334
+ and sometimes only:
335
+
336
+ .. code-block :: xml
337
+
338
+ <connection >default</connection >
339
+
340
+ By default ``connection `` would be an array in the first case and a string
341
+ in the second making it difficult to validate. You can ensure it is always
342
+ an array with with ``fixXmlConfig ``.
343
+
344
+ You can further control the normalization process if you need to. For example
345
+ you may want to allow a string to be set and used as a particular key or several
346
+ keys to be set explicitly. So that, if everything apart from id is optional in this
347
+ config:
348
+
349
+ .. code-block :: yaml
350
+
351
+ connection :
352
+ name : my_mysql_connection
353
+ host : localhost
354
+ driver : mysql
355
+ username : user
356
+ password : pass
357
+
358
+ you can allow the following as well:
359
+
360
+ .. code-block :: yaml
361
+
362
+ connection : my_mysql_connection
363
+
364
+ By changing a string value into an associative array with ``name `` as the key::
365
+
366
+ $rootNode
367
+ ->arrayNode('connection')
368
+ ->beforeNormalization()
369
+ ->ifString()
370
+ ->then(function($v) { return array('name'=> $v); })
371
+ ->end()
372
+ ->scalarValue('name')->isRequired()
373
+ // ...
374
+ ->end()
375
+ ;
376
+
215
377
Validation rules
216
378
----------------
217
379
@@ -278,3 +440,4 @@ Otherwise the result is a clean array of configuration values::
278
440
$processor = new Processor();
279
441
$configuration = new DatabaseConfiguration;
280
442
$processedConfiguration = $processor->processConfiguration($configuration, $configs);
443
+
0 commit comments