Using Zend_Form

After my obsessions with logger and debugger functionality in Zend Framework, for nearly a month I was looking for Zend_Form component. It drove me to look for Zend_Form_Decorator and Zend_Controller_Action_Helper. I did quite a research about them, looked around the code, tried to understand how it worked and how I would be manipulating them to my needs. I have read a lot about forms and helpers and decorators. You will find a some useful links which helped me to understand how it worked. I will try to wrap all I have learned in multiple posts. So the first one will begin with Zend_Form.


First of all, some little info about Zend_Form. From the time it has discovered, it started to create a great impression on every one it uses it. I’m really satisfied with it too. From later on you will see that you write some 50 lines of code to create an only 3 lines of input and 2 lines of form. Most people, (especially people who loves open source) hates auto code generator tools. From a point of view, it’s totally true. But If I can just drag-and-drop a table and only write what the headers will. And if I will waste a couple of hours only to create a grid view, well I guess auto code generation is a great thing. My time is important just like everybody else. I like to spend my time with designing my software more than implementing it. If some tools helps me with this than I love them. That’s one of the reasons I love Visual Studio (not .Net but the IDE).

So why I have told these because I believe that (I also have a dream) Zend_Form is the first step for a drag-and-drop IDEs for PHP. For quite a time, NetBeans was very usefull for Java like language which had their own classes for creating forms instead of html (Swing libraries for example, .Net have it’s own markup for creating forms too). Now, ladies and gentlemen, PHP developers also have such a library: Zend_Form. You should be ready to see some drag-and-drop Zend_Form elements from NetBeans soon I suppose!

Now after an introduction and pointing out the importance of Zend_Form, let’s see how we can use it and why it’s powerful. This slideshow is a perfect introduction to Zend_Form also contains simple examples. You must check that too.

So we go on how a Zend_Form is created and how we can use this form in a controller. Before you continue, I assume that you have a basic understanding of Zend Framework and MVC components. If you are completely new to the ZF, than check here for a basic Hello World example than come back here or go on with the steps there. So let’s continue. We create a simple controller which only contains a Hello World example:

class FooController extends Zend_Controller_Action
{
    public function indexAction()
    {
        $this->view->message = "Hello World!";
    }
}

So you see that I haven’t done anything. I have just created a simple controller  and created some simple view scripts. A little footnote about the message variable, my app/views/scripts/foo/index.phtml file looks like this:

 echo $this->message;

Couldn’t be simpler, right :). So let’s move on how we will create a Zend_Form object. Change your FooController like this:

class FooController extends Zend_Controller_Action
{
    /**
     *
     * @return Zend_Form
     */
    public function createForm()
    {
        $form = new Zend_Form();
        $form->setAction('foo')
             ->setMethod('post');

        $username = new Zend_Form_Element_Text("username");
        $username->setAttrib("size", 10)
                 ->setLabel("Username")
                 ->addValidator("alnum") //Well, there are not alphanumeric characters in my app for username...
                 ->setRequired(true);

        $password = new Zend_Form_Element_Password("password");
        $password->setAttrib("size", 10)
                 ->setLabel('Password')
                 ->setRequired(true); //You want that this field is required for a valid login submission...

        $loginButton = new Zend_Form_Element_Submit("loginButton");
        $loginButton->setLabel("Send");

        $form->addElements(array($username, $password, $loginButton));
        return $form;
    }

    public function indexAction()
    {
        $this->view->message = "Hello World!";

        $form = $this->createForm();
        
        if ($this->getRequest()->isPost()) { //Request object has this isPost() method which returns if post values exists or not...
            if ($form->isValid($_POST)) { //Well how do you think form was validating the given inputs?
                $this->view->message = "Hello " . $form->getValue("username"); //No more Hello World!
            }
        }
        $this->view->form = $form;
    }
}

So here is the changed part: I have added a function named createForm() and than I assigned it to an another Zend_View variable as form. The syntax as you see is pretty easy. You create a new instance set it’s action (I have formerly defined the foo path to my controller via routes). You can add additional elements and finally add them to the form this way. You can add validators like Alnum or EmailAddress, all of them are under Zend_Validate and my view script only changes like this:

echo $this->message;
echo $this->form;

As you will notice all I have done is to print out the form variable which is currently an object. So that’s where the magic functions works and this syntax actually calls the render method of the Zend_Form object. It does wrap the current inputs with dl,dt and dd tags and creates a great output. So It’s pretty easy and less line of code and frustration to do this with plain html. The great part is, you don’t need to handle with errors and other things and you can easily validate the given output (FIEO) and if there are errors you don’t need to put error message controls and other things, they are built-in (really try out entering inputs like, “foo<<” to username field or even submitting both fields with empty strings)!

Everything is pretty cool and easy, right? But, you, just like me, do no favor the use of dl, dt, dd tags because you just don’t like them or see them as burdens or you accept them or want to set some CSS styles on them. So let’s set a class to our input:

//You know what comes before
public function createForm()
{
        $form = new Zend_Form();
        $form->setAction('foo')
            ->setMethod('post');

        $username = new Zend_Form_Element_Text("username");
        $username->setAttrib("size", 10)
                 ->setAttrib("class","textField")
                 ->setLabel("Username")
                 ->addValidator("alnum")
                 ->setRequired(true);

        $password = new Zend_Form_Element_Password("password");
        $password->setAttrib("size", 10)
                 ->setAttrib("class","textField")
                 ->setLabel('Password')
                 ->setRequired(true);

        $loginButton = new Zend_Form_Element_Submit("loginButton");
        $loginButton->setLabel("Send");

        $form->addElements(array($username, $password, $loginButton));
        return $form;
}
//You know what comes later

You can set all the attributes you want with the attribs() method. But still you were unable to save from dl, dt, dd tags. So now we are entering the region of Zend_Form_Decorator. There are lots of built-in Decorators you can use, and I’m sure one of will suit your needs. One of them did for me: Zend_Form_Decorator_HtmlTag.

//Code and code
public function createForm()
{
        $form = new Zend_Form();
        $form->setAction('foo')
             ->addDecorator("HtmlTag", array('tag' => "div")) //With this you are wrapping your form with a div instead of dl
             ->setMethod('post');

        $username = new Zend_Form_Element_Text("username");
        $username->setAttrib("size", 10)
                 ->setAttrib("class","textField")
                 //->addDecorator("Label", array('tag' => "div")) //You can use this for wrapping your label element
                 ->addDecorator('HtmlTag', array('tag' => "div"))
                 ->setLabel("Username")
                 ->addValidator("alnum")
                 ->setRequired(true);

        $password = new Zend_Form_Element_Password("password");
        $password->setAttrib("size", 10)
                 ->setAttrib("class","textField")
                 //->addDecorator("Label", array('tag' => null)) //null means do not wrap it with anything...
                 ->addDecorator('HtmlTag', array('tag' => "div"))
                 ->setLabel('Password')
                 ->setRequired(true);

        $loginButton = new Zend_Form_Element_Submit("loginButton");
        $loginButton->addDecorator('HtmlTag', array('tag' => "div"))
                            ->setLabel("Send");

        $form->addElements(array($username, $password, $loginButton));
        return $form;
}
//More code and code

You see that I set a HtmlTag decorator for all my 3 elements and now they should be wrapped in div elements individually. But wait! Why Submit element is still using DtDdWrapper? Because for submit element in default decorators, you can find it’ but for password and text elements you can’t. The addDecorator() method add a new decorator to the decorator stack (yes you can add as many decorators as you want!). And a little tip about this decorator stack: The order is important! There is a FIFO (First In First Out) rule for the decorators. However if you add the same decorators more then once, only the latest will have effect. You can also set a ViewHelper decorator with which you can point the element to use a predifend html file (so you can define everything with the way you want!). So let’s return to our basic problem on how to remove the DtDdWrapper. You have two options for this: You either remove the decorator with removeDecorator() or reset all the decorators. I will reset all the decorators:

//You know how the other elements are created now...
$loginButton = new Zend_Form_Element_Submit("loginButton");
        $loginButton->removeDecorator("DtDdWrapper") //I'm removing DtDdWrapper and it will not be wrapped with them anymore but let's also see how I can reset them...
                    ->setDecorators(array(array("decorator" => "ViewHelper"), //This one is required...
                                          array("decorator" =>"HtmlTag", "options" => array('tag' => "span", "id" =>"foo")))) //Beware that I can set the attributes of the span element via options...
                    ->setLabel("Send");
//You know what is happening from now on too...

If you do not set the ViewHelper decorator you element will not be parsed too, so beware! But if you put the ViewHelper decorator (which renders the input element) after the HtmlTag decorator you will notice that your input element is not in the div element created by the HtmlTag! That’s because the mentioned FIFO thing. As the input is parsed later, the it’s not wrapped with the first decorator.

There are some other decorators for error, label (you have seen how this one is set) and description related parts of a form. You can check them out too.

Well that’s it for now! I have tried to give the basics on how the Zend_Form works and also covered how the Zend_Decorator works and even some little info about Zend_Validate too. On the next entry I will mention on how we can use one form in multiple controllers with Zend_Controller_Action_Helper.

Update: That’s a bit late to update I know but you should really check out the article of Matthew Weier O’Phinney about Zend_Form and Models in Zend Framework