Skip to content


Array Notation in Zend Form

Overview

Zend Form is a great tool for creating maintainable, reusable, encapsulated forms, unfortunately the learning curve can be steep for even the more experienced programmer. I have seen many cases where programmers will abandon Zend Form and revert back to what they know, html.

Problem:

So, lets say we have a Zend SubForm and we want to reuse the same elements in our page multiple times, for this example I am going to use Members, a Member belongs to an Account and an Account can have more than one Member.

Requirement:

Have a form that allows an end user to add multiple Members to an Account from the same form.

Desired Output: (For simplicity of this example I am using only 1 element)

<ul>
    <li><input name="member[1][first_name]" size="30" value=""></li>
    <li><input name="member[2][first_name]" size="30" value=""></li>
    <li><input name="member[3][first_name]" size="30" value=""></li>
</ul>

Solution:

In order to accomplish this, we will make 2 forms, a SubForm class and a Form class.

SubForm Class:

class Default_Form_SubForm_AddMember extends Zend_Form_SubForm
{
	const FIRST_NAME 		= "first_name";
 
	protected $rowNumber = 1;
 
	public function init()
	{
		$decorators = array(
			'ViewHelper',
			array('HtmlTag', array('tag' => 'li', 'class' => 'form_field'))			
		);
 
		/*
		 * We want array notation, so we will need to do a belongs to here.
		 */
		$this->setElementsBelongTo("member[{$this->rowNumber}]");
 
		$this->addElement("text", self::FIRST_NAME, array("size" => 20, "title" => ""))
			->getElement(self::FIRST_NAME)
			->setDecorators($decorators)
			->addValidator("Alnum", false, array(true))
			->addFilter('StripTags')
			->addValidator("StringLength", false, array("min" => 2, "max" => 100));
	}
 
	public function setRowNumber($num)
	{
		$this->rowNumber = (int) $num;
		return $this;
	}
}

Form Class:

class Default_Form_Member extends Zend_Form
{
	const SUBMIT_BUTTON = "submit";
	protected $max = 10;
 
	public function init()
	{
		$this->addMemberForms();
 
		/*
		 * Left out the rest of the class for simplicity
		 */
 
	}
 
	public function addMemberForms()
	{
 
		for($i=0; $i < $this->max; $i++) {
			$key = "member_". $i;
                     /*
                       * Add Subform passing in current row number as well as decorate
                       * the subform with ul
                       */                     
			$subform = new Account_Form_AddMemberSubForm(array("RowNumber" => ($i+1)));
			$this->addSubForm($subform, $key)
				->getSubForm($key)
				->clearDecorators()
				->addDecorator('FormElements')
				->addDecorator('HtmlTag', array("tag" => "ul"));
		}
	}
 
    /*
     * Set the Max fields to show, this value is passed to the form constructor
     * new form(array('Max' => 10));
     */	
	public function setMax($max)
	{
		$this->max = $max;
 
                return $this;
	}
}

Posted in PHP, Zend Framework 1.

3 Responses

Stay in touch with the conversation, subscribe to the RSS feed for comments on this post.

  1. nuKs said

    Thanks a lot :O I was looking for this :)

  2. Allan Chappell said

    Thanks for the short, sweet, simple, and easy to follow post. It was exactly what I needed. I didn’t realize you could do array notation in BelongTo.

  3. Alf said

    Oh my! First post I found that explains how to achieve this. I made such a mess with my code trying to get the right display. Thank you so much!

Some HTML is OK

(required)

(required, but never shared)

or, reply to this post via trackback.