#tree and #parents

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.

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'] = array(
'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. #parentsis 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:

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 #treeis 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 #parentsto 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 #parentsdoes 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'] = array(...);

The element 'beer' will always have:

'#array_parents' => array('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.