Zend Form Element, set name allowBrackets

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Zend Form Element, set name allowBrackets

Mikael Abrahamsson-3
When creating a new instance of a zend form element how to you give it  
a name with brackets?
The Zend_Form_Element::setName() method calls the  
Zend_Form_Element::filterName() method which taks as a second argument  
$allowBrackets boolean.

So how do I set the name with brackets?


Reply | Threaded
Open this post in threaded view
|

Re: Zend Form Element, set name allowBrackets

weierophinney
Administrator
-- Mikael Abrahamsson <[hidden email]> wrote
(on Sunday, 01 March 2009, 11:15 AM +0100):
> When creating a new instance of a zend form element how to you give it a
> name with brackets?
> The Zend_Form_Element::setName() method calls the  
> Zend_Form_Element::filterName() method which taks as a second argument  
> $allowBrackets boolean.
>
> So how do I set the name with brackets?

So, first off, names are not allowed to have brackets internally so that
a variety of other features will work (overloading access, primarily).

That said, you *can* force brackets to appear in the output in a couple
of different ways.

  * If you want brackets for allowing multiple values to be captured --
    i.e., a name like 'foo[]' -- turn on the isArray property:

        $element->setIsArray(true); // or pass a true value to the
                                    // "isArray" key during
                                    // instantiation

  * If you want the value to be a key in another value, e.g.,
    "bar[foo]", then you need to tell the element it belongs to another
    value:

        $element->setBelongsTo('bar'); // or pass the value to the
                                       // 'belongsTo' key during
                                       // instantiation

  * If you use sub forms, array notation happens by default; all
    elements "belongTo" the name of the sub form


--
Matthew Weier O'Phinney
Software Architect       | [hidden email]
Zend Framework           | http://framework.zend.com/
Reply | Threaded
Open this post in threaded view
|

Re: Zend Form Element, set name allowBrackets

Chandu
Hello - How to render element in the phtml file which we set that element as $element->setIsArray(true); in the controller.

Our goal is to have the name as array for a text box field

Thanks inadvance
- Chandu
Reply | Threaded
Open this post in threaded view
|

Re: Zend Form Element, set name allowBrackets (with solution for associative arrays)

diggie
In reply to this post by weierophinney
Hi Matthew,

Thanks for the explanation. Your post has been very helpful in trying to get Zend_Form to work with dynamically generated elements. However I'm working with repetitive associative array names in a form that uses display groups. And through the gates of Zend_Form-hell we go... ;)

It has taken me several hours to exhaust many possibilities and actually solve this problem, and I only succeeded in a somewhat uncharming way. (solution below)

(BTW, I'm using ZF 1.11.3)

weierophinney wrote
That said, you *can* force brackets to appear in the output in a couple
of different ways.

  * If you want brackets for allowing multiple values to be captured --
    i.e., a name like 'foo[]' -- turn on the isArray property:

        $element->setIsArray(true); // or pass a true value to the
                                    // "isArray" key during
                                    // instantiation
This works nicely, but only allows you to have an ordinal structure like <input name="foo[]" />, and not associative <input name="foo[bar]" />, which is what I need.

weierophinney wrote
  * If you want the value to be a key in another value, e.g.,
    "bar[foo]", then you need to tell the element it belongs to another
    value:

        $element->setBelongsTo('bar'); // or pass the value to the
                                       // 'belongsTo' key during
                                       // instantiation
This works partially. It does not work if you specify recurring names. See the next (highly simplified) example (I'm using a database and some iteration in the real situation):
   // create an array containing all elements:
   $elementsArray[1] = $this->createElement("text", "foo");
   $elementsArray[1]->setBelongsTo("bar1");
   $elementsArray[2] = $this->createElement("text", "foo");
   $elementsArray[2]->setBelongsto("bar2");

   // add the elements to the form, inside the display group:
   $this->getDisplayGroup("baz")->addElements($elementsArray);

One would want this to render:
   <fieldset id="fieldset-baz">
      <input type="text" name="bar1[foo]" value="" />
      <input type="text" name="bar2[foo]" value="" />
   </fieldset>

Instead, during addElements(), the first element will get overwritten by the last, and output is:
   <fieldset id="fieldset-baz">
      <input type="text" name="bar2[foo]" value="" />
   </fieldset>

This is quite logical ofcourse, because Zend_Form uses the name itself as the member variable pointing to the Zend_Form_Element object.

==sidenote==
To circumvent this I've tried passing "bar1[foo]" and "bar2[foo]" as names for the constructor, so I could build a custom decorator to render the right names, but Zend_Form simply seems to strip everything except a-z. This leaves "bar" as the name, without the number part, although it shouldn't be a problem for variable names in PHP, as long as the name doesn't start with a number.
I'm not much surprised that bar1[foo] cannot be used as a variable name, although Zend_Form could use some logic to actually create an array to store the element in.

I've also tried "bar1.foo", "bar1|foo" and "bar1_foo", with the first also stripping back to "person" and the others actually throwing a Zend_Form_Exception with message 'Invalid name provided; must contain only valid variable characters and be non-empty'. This exception should also be thrown in all other "non a-z"-cases then, I would say.
Also, bar1_foo is a perfectly valid php variable name again.

==/sidenote==

The solution however, is in this direction (see below)

weierophinney wrote
  * If you use sub forms, array notation happens by default; all
    elements "belongTo" the name of the sub form
I have tried to create subforms for each group, which actually works as expected.

However, the problem was still not solved: like I said, the form in which these fields have to go uses display groups.
Putting a subform in a display group is not supported (I'd really like a $this->getDisplayGroup("baz")->addForm($mySubForm); or something similar). Too bad...

Still this wouldn't be the biggest of problems as you can layout subforms within fieldsets easily and have them look identical to display groups. But the subforms actually overwrite/replace the display groups in the form! This may very well be a bug in ZF, I haven't checked the ZF code yet...
Note: the subforms had very different names than the display groups. I've checked... ;)


In the end I came up with this solution:

   // create an array containing all elements:
   $elementsArray[1] = $this->createElement("text", "foobar1");
   $elementsArray[1]->setBelongsTo("bar1")->setAttrib("actual_name", "foo");
   $elementsArray[2] = $this->createElement("text", "foobar2");
   $elementsArray[2]->setBelongsto("bar2")->setAttrib("actual_name", "foo");

   // add the elements to the form, inside the display group:
   $this->getDisplayGroup("baz")->addElements($elementsArray);

   // And now for the magic trick:
   // As the elements have been already been assigned to member variables in the Zend_Form,
   // we can now change their names to the proper names, and they will be rendered OK.
   foreach ($this->getDisplayGroup("baz") as $element) {
      $element->setName($element->getAttrib("actual_name"));
   }

It turned out somewhat of a hack, but it works nicely.

Now, is this hack the only way? Or is there a simpler or more elegant way I'm not seeing?
If not, I still hope this 'trick' will help others to fix similar problems...

Best regards,
diggie
Reply | Threaded
Open this post in threaded view
|

Re: Zend Form Element, set name allowBrackets (with solution for associative arrays)

diggie
Edit: By changing the name of the elements, $form->populate() seems to skip the fields altogether, although the validation still seems to work. So you get all empty input fields for all elements that have been added this way.
Setting the value to the POSTed value doesn't work, nor does setting the defaults through the form object.

Too bad, back to the drawingboard for me...

-- diggie