phpzend-frameworkzend-form

How can I set the order of Zend Form Elements and avoid duplicates


In Zend Form, if two elements have the same order, then Zend will totally ignores the second element (instead of displaying it under the first). Take the following code as an example. Notice that the City and Zip Code elements have the same order of 4

    $address = new Zend_Form_Element_Textarea('address');
    $address->setLabel('Address')
            ->setAttrib('cols', 20)
            ->setAttrib('rows', 2)
            ->setOrder(3)
            ;

    $city = new Zend_Form_Element_Text('city');
    $city->setLabel('City')
         ->setOrder(4)
          ;

    $postal = new Zend_Form_Element_Text('postal');
    $postal->setLabel('Zip Code')
           ->setOrder(4);

When this form renders, the Zip Code element is nowhere to be found.

If I want to set elements like a buttons dynamically, but tell it to render at the end of the form, how would I do this and not run into the problem of having two elements with the same order?

public function addSubmitButton($label = "Submit", $order = null)
{
    $form_name = $this->getName();

    // Convert Label to a lowercase no spaces handle
    $handle = strtolower(str_replace(" ","_",$label));

    $submit = new Zend_Form_Element_Submit($handle);
    $submit->setLabel($label)
           ->setAttrib('id', $form_name . "_" . $handle)
            ;

    /////////    Set the button order to be at the end of the form   /////////
    $submit->setOrder(??????);


    $this->addElement($submit);

}

Solution

  • If you really need to use the setOrder() method, I'd work with order numbers 10, 20, 30, 40, ... This way it will be easy to add elements in between already set Elements.

    Furthermore, in order to avoid using order-numbers twice, you could use an array, where you store all the numbers from 1 to X. Whenever you set an order number, you set it via a method called getOrderNumberFromArray() which returns the next higher or lower order number still available in the array and unsets this array element.

    Alternatively, and maybe even better, you could do getOrder() on the element you want to have before the new element, then increment this order number by X and then loop through the existing form elements and check that the order number doesn't exist yet.

    Or you could just use getOrder() on the Element you want to show before and after the new element and make sure you don't use the same order numbers for the new element.