Zend Framework: Working with Form elements in array notation
Asked Answered
L

4

19

I would like to be able to add a hidden form field using array notation to my form. I can do this with HTML like this:

<input type="hidden" name="contacts[]" value="123" />
<input type="hidden" name="contacts[]" value="456" />

When the form gets submitted, the $_POST array will contain the hidden element values grouped as an array:

array(
    'contacts' => array(
        0 => '123'
        1 => '456'
    )
)

I can add a hidden element to my form, and specify array notation like this:

$form->addElement('hidden', 'contacts', array('isArray' => true));

Now if I populate that element with an array, I expect that it should store the values as an array, and render the elements as the HTML shown above:

$form->populate($_POST);

However, this does not work. There may be a bug in the version of Zend Framework that I am using. Am I doing this right? What should I do differently? How can I achieve the outcome above? I am willing to create a custom form element if I have to. Just let me know what I need to do.

Lateral answered 8/9, 2010 at 23:30 Comment(0)
L
16

To use array notation, you need to specify that the element "belongs to" a parent array:

$form->addElement('hidden', 'contact123', array('belongsTo' => 'contacts', 'value' => '123'));
$form->addElement('hidden', 'contact456', array('belongsTo' => 'contacts', 'value' => '456'));
Lateral answered 15/8, 2011 at 4:26 Comment(2)
this generates <input type="hidden" id="contacts-contact123" value="123" name="contacts[contact123]">, however if you need contacts[123] and number[123] this won't workBangka
I have a variable length array that needed to be added to my zend pagination controls. I did the following: $this->formHidden($key . "[" . $k . "]", $v, array('belongsTo' => $key));Neil
S
19

You have to use subforms to get the result you seek. The documentation was quite a ride but you can find it here

Using what I found there I constructed the following formL

 <?php

class Form_Test extends Zend_Form {

    public function init() {
        $this->setMethod('post');
        $this->setIsArray(true);

        $this->setSubFormDecorators(array(
            'FormElements',
            'Fieldset'
        ));

        $subForm = new Zend_Form(array('disableLoadDefaultDecorators' => true));

        $subForm->setDecorators(array(
            'FormElements',
        ));

        $subForm->addElement('hidden', 'contacts', array(
            'isArray' => true,
            'value' => '237',
            'decorators' => Array(
                'ViewHelper',
            ),
        ));

        $subForm2 = new Zend_Form(array('disableLoadDefaultDecorators' => true));

        $subForm2->setDecorators(array(
            'FormElements',
        ));

        $subForm2->addElement('hidden', 'contacts', array(
            'isArray' => true,
            'value' => '456', 'decorators' => Array(
                'ViewHelper',
            ),
        ));

        $this->addSubForm($subForm, 'subform');
        $this->addSubForm($subForm2, 'subform2');


        $submit = new Zend_Form_Element_Submit('submit');
        $submit->setValue('Submit');

        $this->addElement('submit', 'submit');
    }

}

Wich outputs this html:

<form enctype="application/x-www-form-urlencoded" method="post" action=""><dl class="zend_form">
<input type="hidden" name="contacts[]" value="237" id="contacts">

<input type="hidden" name="contacts[]" value="456" id="contacts">

<dt id="submit-label">&nbsp;</dt><dd id="submit-element">

<input type="submit" name="submit" id="submit" value="submit"></dd></dl></form>

And when submited the post looks like:

array(2) {
  ["contacts"] => array(2) {
    [0] => string(3) "237"
    [1] => string(3) "456"
  }
  ["submit"] => string(6) "submit"
}

So thats how you can create the kind of forms you seek. Hope this helps! if you have a question post a comment!

Its quite hackish if you ask me. You basically create subforms but disable there form decorators so just the element gets output. Since the identical contacts[] elements are in different form object zend does'nt overwrite them and it works. But yeah..

Edit: changed it a bit to remove labels and garbage arount the hidden inputs.

Shrub answered 9/9, 2010 at 0:53 Comment(2)
+1 to you for the answer. ;-) But -1 to ZF for requiring this. Subforms just to create these hidden fields in array notation? Ugh. Better would be a configuration key you could set on the element that would initiate all this subform madness for you. Guess we could implement a custom element that does this.Unobtrusive
@DavidW Yeah I always use viewhelpers or just roll my own forms out. Such a pain to work with decorators and leverage the zend_form. But ZF 2.0 has much better forms I think(hope!). Thansk for the upvote.Shrub
L
16

To use array notation, you need to specify that the element "belongs to" a parent array:

$form->addElement('hidden', 'contact123', array('belongsTo' => 'contacts', 'value' => '123'));
$form->addElement('hidden', 'contact456', array('belongsTo' => 'contacts', 'value' => '456'));
Lateral answered 15/8, 2011 at 4:26 Comment(2)
this generates <input type="hidden" id="contacts-contact123" value="123" name="contacts[contact123]">, however if you need contacts[123] and number[123] this won't workBangka
I have a variable length array that needed to be added to my zend pagination controls. I did the following: $this->formHidden($key . "[" . $k . "]", $v, array('belongsTo' => $key));Neil
C
8

This indeed seems to be a bug in Zend Framework - the value attribute for an element is properly set to array, but it's ignored when the element renders - it just uses$this->view->escape($value) to output element's html. I've solved this by implementing a custom helper for such elements:

class My_View_Helper_HiddenArray extends Zend_View_Helper_FormHidden 
{
    public function hiddenArray($name, $value = null, array $attribs = null)
    {
        if (is_array($value)) {
            $elementXHTML = '';
            // do not give element an id due to the possibility of multiple values
            if (isset($attribs) && is_array($attribs) && array_key_exists('id', $attribs)) {
                unset($attribs['id']);
            }

            foreach ($value as $item) {
                $elementXHTML .= $this->_hidden($name, $item, $attribs);
            }
            return $elementXHTML;

        } else {
            return $this->formHidden($name, $value, $attribs);
        }
    }
}

Which, when used the next way:

$contacts = $form->createElement('hidden', 'contacts')
->setIsArray(true)
->setDecorators(array(
    array('ViewHelper', array('helper' => 'HiddenArray')),
));
$form->addElement($contacts);

generates the needed output.

The reason to extend Zend_View_Helper_FormHidden here is just to be able to call the default behaviour if no array value is set ( return parent::formHidden($name, $value, $attribs) ).

Hope this helps someone :)

Clothespin answered 31/1, 2012 at 15:56 Comment(1)
Yes, I prefer this answer :). Extending Zend Framework core files was always a fun for me.Judenberg
R
0

For the newer versions of ZF you should use https://framework.zend.com/manual/2.1/en/modules/zend.form.elements.html#multicheckbox

Rustice answered 6/3, 2019 at 16:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.