diff --git a/components/config/definition.rst b/components/config/definition.rst index fb0d75db572..255c13062c8 100644 --- a/components/config/definition.rst +++ b/components/config/definition.rst @@ -212,6 +212,168 @@ For all nodes: ``cannotBeOverwritten()`` don’t let other configuration arrays overwrite an existing value for this node +Appending sections +------------------ + +If you have a complex configuration to validate then the tree can grow to +be large and you may want to split it up into sections. You can do this by +making a section a separate node and then appending it into the main tree +with ``append()``:: + + public function getConfigTreeBuilder() + { + $treeBuilder = new TreeBuilder(); + $rootNode = $treeBuilder->root('database'); + + $rootNode + ->arrayNode('connection') + ->children() + ->scalarNode('driver') + ->isRequired() + ->cannotBeEmpty() + ->end() + ->scalarNode('host') + ->defaultValue('localhost') + ->end() + ->scalarNode('username')->end() + ->scalarNode('password')->end() + ->booleanNode('memory') + ->defaultFalse() + ->end() + ->end() + ->append($this->addParametersNode()) + ->end() + ; + + return $treeBuilder; + } + + public function addParametersNode() + { + $builder = new TreeBuilder(); + $node = $builder->root('parameters'); + + $node + ->isRequired() + ->requiresAtLeastOneElement() + ->useAttributeAsKey('name') + ->prototype('array') + ->children() + ->scalarNode('name')->isRequired()->end() + ->scalarNode('value')->isRequired()->end() + ->end() + ->end() + ; + + return $node; + } + +This is also useful to help you avoid repeating yourself if you have sections +of the config that are repeated in different places. + +Normalization +------------- + +When the config files are processed they are first normalized, they are then +merged and then the tree is used to validate the resulting array. The normalization +is to remove some of the differences that result from different configuration formats, +mainly the differences between Yaml and XML. + +The separator used in keys is typically ``_`` in Yaml and ``-`` in XML. For +example, ``auto_connect`` in Yaml and ``auto-connect``. The normalization would +make both of these ``auto_connect``. + +Another difference between Yaml and XML is in the way arrays of values may +be represented. In Yaml you may have: + +.. code-block:: yaml + + twig: + extensions: ['twig.extension.foo', 'twig.extension.bar'] + +and in XML: + +.. code-block:: xml + + + twig.extension.foo + twig.extension.bar + + +This difference can be removed in normalization by pluralizing the key used +in XML. You can specify that you want a key to be pluralized in this way with +``fixXmlConfig()``:: + + $rootNode + ->fixXmlConfig('extension') + ->children() + ->arrayNode('extensions') + ->prototype('scalar')->end() + ->end() + ->end() + ; + +If it is an irregular pluralization you can specify the plural to use as +a second argument:: + + $rootNode + ->fixXmlConfig('child', 'children') + ->children() + ->arrayNode('children') + ->end() + ; + +As well as fixing this it ensures that single xml elements are still turned into an array. +So you may have: + +.. code-block:: xml + + default + extra + +and sometimes only: + +.. code-block:: xml + + default + +By default ``connection`` would be an array in the first case and a string +in the second making it difficult to validate. You can ensure it is always +an array with with ``fixXmlConfig``. + +You can further control the normalization process if you need to. For example +you may want to allow a string to be set and used as a particular key or several +keys to be set explicitly. So that, if everything apart from id is optional in this +config: + +.. code-block:: yaml + + connection: + name: my_mysql_connection + host: localhost + driver: mysql + username: user + password: pass + +you can allow the following as well: + +.. code-block:: yaml + + connection: my_mysql_connection + +By changing a string value into an associative array with ``name`` as the key:: + + $rootNode + ->arrayNode('connection') + ->beforeNormalization() + ->ifString() + ->then(function($v) { return array('name'=> $v); }) + ->end() + ->scalarValue('name')->isRequired() + // ... + ->end() + ; + Validation rules ---------------- @@ -278,3 +440,4 @@ Otherwise the result is a clean array of configuration values:: $processor = new Processor(); $configuration = new DatabaseConfiguration; $processedConfiguration = $processor->processConfiguration($configuration, $configs); +