Skip to content

Documented the useAttributeAsKey() method #5314

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 14, 2015
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 136 additions & 21 deletions components/config/definition.rst
Original file line number Diff line number Diff line change
Expand Up @@ -200,43 +200,158 @@ Array Node Options

Before defining the children of an array node, you can provide options like:

``useAttributeAsKey()``
Provide the name of a child node, whose value should be used as the key in the resulting array.
``requiresAtLeastOneElement()``
There should be at least one element in the array (works only when ``isRequired()`` is also
called).
``addDefaultsIfNotSet()``
If any child nodes have default values, use them if explicit values haven't been provided.
If any child nodes have default values, use them if explicit values haven't
been provided.
``requiresAtLeastOneElement()``
There should be at least one element in the array (works only when
``isRequired()`` is also called).
``useAttributeAsKey()``
Provide the name of a child node, whose value should be used as the key in
the resulting array. This method also defines the way config array keys are
treated, as explained in the following example.

An example of this::
A basic prototyped array configuration can be defined as follows::

$rootNode
$node
->fixXmlConfig('driver')
->children()
->arrayNode('parameters')
->isRequired()
->requiresAtLeastOneElement()
->useAttributeAsKey('name')
->arrayNode('drivers')
->prototype('scalar')->end()
->end()
->end()
;

When using the following YAML configuration:

.. code-block:: yaml

drivers: ['mysql', 'sqlite']
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't we use pdo_sqlite and pdo_mysql, cause they were used in doctrine?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example isn't about doctrine, I choose a different value on purpose (honestly, I didn't want to take databases as an example, but couldn't come up with something else)


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this also possible?

drivers:
  - mysql
  - sqlite

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes it is, because this is exactly the same in YAML, so the Config component receives the same input.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, but we don't want to write this example explicitly, too?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see no need in doing that, this chapter is teaching you the Config component, not the Yaml syntax :)

Or the following XML configuration:

.. code-block:: xml

<driver>msyql</driver>
<driver>sqlite</driver>

The processed configuration is::

Array(
[0] => 'mysql'
[1] => 'sqlite'
)

A more complex example would be to define a prototyped array with children::

$node
->fixXmlConfig('connection')
->children()
->arrayNode('connections')
->prototype('array')
->children()
->scalarNode('value')->isRequired()->end()
->scalarNode('table')->end()
->scalarNode('user')->end()
->scalarNode('password')->end()
->end()
->end()
->end()
->end()
;

In YAML, the configuration might look like this:
When using the following YAML configuration:

.. code-block:: yaml

database:
parameters:
param1: { value: param1val }
connections:
- { table: symfony, user: root, password: ~ }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for the example, i would prefer database instead of table

- { table: foo, user: root, password: pa$$ }

Or the following XML configuration:

.. code-block:: xml

<connection table="symfony" user="root" password="null" />
<connection table="foo" user="root" password="pa$$" />

The processed configuration is::

Array(
[0] => Array(
[table] => 'symfony'
[user] => 'root'
[password] => null
)
[1] => Array(
[table] => 'foo'
[user] => 'root'
[password] => 'pa$$'
)
)

The previous output matches the expected result. However, given the configuration
tree, when using the following YAML configuration:

.. code-block:: yaml

connections:
sf_connection:
table: symfony
user: root
password: ~
default:
table: foo
user: root
password: pa$$

The output configuration will be exactly the same as before. In other words, the
``sf_connection`` and ``default`` configuration keys are lost. The reason is that
the Symfony Config component treats arrays as lists by default.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that actually true when using the YAML format? Isn't the useAttributeAsKey() method only necessary when using the XML format because XML itself does not know anything like hashes?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@xabbuh actually, there is an inconsistency in Symfony currently: if we need to merge lists coming from multiple files, the keys are lost (merging them in a new list indexed numerically). However, in case merging is not necessary (a single file configures this list), we currently don't reset keys


In order to maintain the array keys use the ``useAttributeAsKey()`` method::

$node
->fixXmlConfig('connection')
->children()
->arrayNode('connections')
->prototype('array')
->useAttributeAsKey('name')
->children()
->scalarNode('table')->end()
->scalarNode('user')->end()
->scalarNode('password')->end()
->end()
->end()
->end()
->end()
;

The argument of this method (``name`` in the example above) defines the name of
the attribute added to each XML node to differentiate them. Now you can use the
same YAML configuration showed before or the following XML configuration:

.. code-block:: xml

In XML, each ``parameters`` node would have a ``name`` attribute (along with
``value``), which would be removed and used as the key for that element in
the final array. The ``useAttributeAsKey`` is useful for normalizing how
arrays are specified between different formats like XML and YAML.
<connection name="sf_connection"
table="symfony" user="root" password="null" />
<connection name="default"
table="foo" user="root" password="pa$$" />

In both cases, the processed configuration maintains the ``sf_connection`` and
``default`` keys::

Array(
[sf_connection] => Array(
[table] => 'symfony'
[user] => 'root'
[password] => null
)
[default] => Array(
[table] => 'foo'
[user] => 'root'
[password] => 'pa$$'
)
)

Default and required Values
---------------------------
Expand Down