ZF-2563: Allow array notation in form element names

Description

A common pattern used by those developing forms is to assign elements as array keys:


This is done to group related data, as well as on forms that may have repeated sets of form data (e.g., a 'todo' application, that might create a new set of data for each todo item).

Currently, this is not supported in Zend_Form, and the support within Zend_View_Helper_FormElement is slightly buggy.

In Zend_View_Helper_FormElement can create names with array notation without a problem. However, since the name is used as the id when no id is present, this causes invalid ids. Additionally, it does not currently look to see if the provided value is an array, nor if the element's name exists in the array, leading to errors and buggy output.

Within Zend_Form, we cannot allow names with array notation due to the fact that we overload; array notation will cause interpreter issues with PHP.

The solution to this is to use sub forms. My proposal is to add a 'belongsTo' property to Zend_Form_Element. SubForms, when rendering, would then set the 'belongsTo' property of each element. Decorators that need to be array-aware would then build the name using the value of this property:


$name = $element->getBelongsTo() . '['
      . $element->getName()
      . ']';

Additionally, it could set the id, if not previously set, by concatenating the belongsTo property and the name with a dot separator:


$id = $element->getBelongsTo() . '.'
    . $element->getName();

Finally, the value would be passed by the decorator based on the element value, thus bypassing the issues in Zend_View_Helper_FormElement.

Comments

This is now checked into the repo in r7793.

Usage is as follows:


$foo = new Zend_Form_SubForm();
$foo->setElementsBelongTo('foo')
    ->setElements(array(
        'bar' => 'text',
        'baz' => 'text'
    ));
echo $foo;

which results in HTML something like:


When data is submitted from such a form, the 'foo' key will be passed to the subform, which will use that array in its own isValid() call -- effectively namespacing the elements.

Please give this a try and comment on any issues.

I've verified that all works as expected; labels are created with the appropriate ids, validation works as expected, and getValues() retrieves values as expected. As an example, I've created a sample controller and login form showing potential usage.

With

array( 'ViewHelper', array(array('td' => 'HtmlTag'), array('tag' => 'td', 'style' => 'width: 360px;')), array('Label', array('tag' => 'td', 'requiredSuffix' => ' *')), array(array('tr' => 'HtmlTag'), array('tag' => 'tr')), array(array('tbody' => 'HtmlTag'), array('tag' => 'tbody')), array(array('table' => 'HtmlTag'), array('tag' => 'table', 'class' => 'tiny')), array(array('separator' => 'HtmlTag'), array('tag' => 'div', 'class' => 'separator')) )

element decorators, I get duplicated label (td) ids. I have 3 subforms under main form rendered on the page.