#tree and #parents
Drupal 7 will no longer be supported after January 5, 2025. Learn more and find resources for Drupal 7 sites
Normally when working with submitted data in $form_state['values'] the data is flattened and does not maintain the structure of the $form array used to generate the form. This behavior can be changed using the #tree
property.
The #tree
property is a boolean (default FALSE) used for collections of form elements. It is used in part along with #parents
to determine the name that the <input>
element in the HTML form will receive, and therefore also influences how data can be accessed in the $form_state
array when a form is submitted.
Consider the following form array:
$form['name'][1]['first'] = [
// text field ...
];
$form['name'][1]['last'] = [
// text field ...
];
$form['name'][2]['first'] = [
// text field ...
];
$form['name'][2]['last'] = [
// text field ...
];
When rendered to HTML this would result in a form with 4 textfields. The names of those elements will vary depending on the use of #tree. By default, the name attribute is taken from the value of the last key, so in effect you'll end up with two input fields with a name attribute of "first" and 2 with a name attribute of last. Furthermore, by default the form API will flatten the form structure when processing submitted values. The above code would result in:
$form_state['values'] = [
'first' => '', // Value of name field
'last' => '', // Value of last field
];
Notice there are only 2, and not 4 values in the array? In this case you'll only have access to the submitted values of the last element defined in the $form
array with that key.
If however, you set $form['name']['#tree'] = TRUE;
, or as long as the #tree
attribute is TRUE at any point in the tree, the form element is aware that it is in a tree, and traverses the tree towards the root (from first, to 1, to name). Along the way, the names of the elements passed are stored in#parents
. #parents
is used to create the name/ID of the HTML form element itself.
Example:
<input name="first">
vs. <input name="name[1][first]">
With #tree
set to TRUE the structure of the $form
array is maintained and $form_state['values']
would be as follows:
$form_state['values'] = [
'name' => [
1 => ['first' => '', 'last' => ''],
2 => ['first' => '', 'last' => ''],
],
];
Cascading of #tree
There are shortcuts to traversing the full tree each time. If you set #tree = TRUE
at a closer point to the root of the tree, as in:
<?php
$form['foo']['#tree'] = TRUE
?>
and you have not specifically set #tree
anywhere else, then it will cascade and make all of the sub-elements' #tree = TRUE
. This is very useful because otherwise you would need to write #tree = TRUE
for each element in the tree.
Common use of #tree
A common use of #tree
is fieldsets. Another example is the checkbox element type where #tree
is set to TRUE internally before expanding to multiple checkbox elements.
Common use of #parents
You can set #parents
manually, but the need for this is rare. More common is to read #parents
to determine where in the form tree the current element is. Setting #parents
does not affect the rendering of the form; that's decided by the indexes. However, setting #parents
does affect placement of $form_values
, as can be seen from filter_form().
#parents vs. #array_parents
#array_parents
contains the actual parent array keys of an element in a form structure and is useful if you need to locate an item in the $form
array.
#parents
always contains the parent array keys of an element in the submitted form values and is heavily influenced as we saw above by the use of #tree
.
For example:
$form['foo']['bar']['beer'] = [...];
The element 'beer' will always have:
'#array_parents' => ['foo', 'bar', 'beer']
This is heavily influenced by previously defined #parents further up the tree, or, when speaking of tree, it's also affected by whether some element above the element defined #tree, or, whether the element itself defines #tree.
For example:
$form['foo']['bar'] = [...];
will end up in
$form_state['values']['bar'] = '...';
and we'll see
'#parents' => ['bar']
For example:
$form['foo']['bar'] = [...];
$form['foo']['#tree'] = TRUE;
will end up in
$form_state['values']['foo']['bar'] = '...';
and we'll see
'#parents' => ['foo', 'bar']
For example:
$form['foo']['bar'] = [...];
$form['foo']['#parents'] = ['beer'];
will end up in
$form_state['values']['beer']['bar'] = '...';
and we'll see
'#parents' => ['beer', 'bar']
For example:
$form['foo']['bar'] = ['#default_value' => 'bar'];
$form['foo']['#tree'] = TRUE;
$form['foo']['bar']['beer'] = ['#default_value' => 'beer'];
$form['foo']['bar']['beer']['#tree'] = FALSE;
will end up in
$form_state['values']['foo']['bar'] = 'bar';
$form_state['values']['beer'] = 'beer';
and we'll see
'#parents' => ['foo', 'bar']
'#parents' => ['beer']
Help improve this page
You can:
- Log in, click Edit, and edit this page
- Log in, click Discuss, update the Page status value, and suggest an improvement
- Log in and create a Documentation issue with your suggestion