Creating good looking Zend forms

Published on: August 02, 2013 Written by: Thokozani Mhlongo

Today we are going to be covering how to use the Zend_Form object to create good looking forms. Zend has a nice way of handling forms. There are validators, amongst other good things, that inherent in the framework for forms so it really saves you the time and effort of building your own. I would strongly suggest you make use of them too. But what I don't like about these forms is the styling. If you've used Zend before then you must know what a pain it could be to get your forms looking the way you want them to look. You might be tempted to create your forms the old fashioned mark-up style way. But then you miss out on all the goodies that the Zend_Form comes with. So what then? Well in this post I will be touching a bit on Zend decorators and I will show you how to get the best of both worlds.

Creating a Zend form

There is a quick start document on the Zend website of how to creating Zend forms if you haven't done this before. We will be creating a simple registration form that requires a name, email, and password. This is our form named RegisterForm.php:

<?php

class Application_Form_RegisterForm extends Zend_Form
{

    public function init()
    {
        /* Form Elements & Other Definitions Here ... */
        $name = new Zend_Form_Element_Text("name");
        $name->addValidator('NotEmpty'); //Validation for not empty
        $name->setRequired(true); //This field is required
        $name->setLabel("Name:"); //The field label
        
        $email = new Zend_Form_Element_text('email');
        $email->addValidator('NotEmpty');
        $email->addValidator('EmailAddress'); //Validation for email
        $email->addFilter('StringToLower'); //Characters should be in lowercase for email
        $email->setRequired(true);
        $email->setLabel("Email:");
        
        $password = new Zend_Form_Element_Password('password');
        $password->setRequired(true);
        $password->setLabel("Password");
        
        $submit = new Zend_Form_Element_Submit('submit');
        $submit->setLabel('Register');
        
        $this->addElements(array($name, $email, $password, $submit));
    }

}

?>

 

Let's instantiate our form inside our controller and use in our view. This is our IndexController.php file:

<?php

class IndexController extends Zend_Controller_Action
{
    protected $_registrationForm;

    public function preDispatch() {
        parent::preDispatch();

        //Instantiate the form
        $this->_registrationForm = new Application_Form_RegisterForm();
    }
    
    public function init() {
        /* Initialize action controller here */
    }

    public function indexAction() {
        
        if($this->_request->isPost()) {
            $data = $this->_request->getPost(); //Get post data from request object
            if($this->_registrationForm->isValid( $data )) { //This checks if all validators are satisfied
                //Don't show the form again. Get the values from the form object
                $name       = $this->_registrationForm->getValue('name');
                $email      = $this->_registrationForm->getValue('email');
                $password   = $this->_registrationForm->getValue('password');
                
                echo "<p>Name: {$name}<p/>";
                echo "<p>Email: {$email}<p/>";
                echo "<p>Password: {$password}<p/>";
            } else {
                $this->view->form = $this->_registrationForm; //Send form to the view with errors
            }
        } else {
            $this->view->form = $this->_registrationForm; //Send form to the view
        }
    }
}

?>

 

In our index action of our controller we have to check if the post was submitted first. The line:

if($this->_registrationForm->isValid( $data ))

checks if the form had been submitted without any problems since we have set validators that the person filling the form has to satisfy. If you run the app on your browser and you submit fields without values you will see a bunch of errors popping up just under your fields.

Now lets echo the form out on our index.phtml file located iin views/scripts/index.. This is how the file looks like

<?php echo $this->form ?>

 

Now if you run this on your browser it should give you a basic form with each HTML element on a new line. What's important to notice about this form is the markup. This is how it looks:

Zend form markup

 

The form is surrounded by <dl> and <dt> elements which makes the form look that way. In order to remove these elements we have to make use Zend decorators. Zend decorators lets us remove or add markup to structure our forms the way we want. But...this can be complex especially for real good looking forms. We will use these decorators to only remove those unwanted elements on the screenshot above. We only want the <input/> and <label> form elements on this form.

Adding decorators to our Zend form

Let's modify our RegisterForm.php file and remove that unwanted markup. This is our modified RegisterForm.php:

<?php

class Application_Form_RegisterForm extends Zend_Form
{
    public function init()
    {
        /* Form Elements & Other Definitions Here ... */
        $name = new Zend_Form_Element_Text("name");
        $name->addValidator('NotEmpty', true); //Validation for not empty
        $name->setRequired(true); //This field is required
        $name->setLabel("Name:"); //The field label
        
        $email = new Zend_Form_Element_text('email');
        $email->addValidator('NotEmpty', true);
        $email->addValidator('EmailAddress'); //Validation for email
        $email->addFilter('StringToLower'); //Characters should be in lowercase for email
        $email->setRequired(true);
        $email->setLabel("Email:");
        
        $password = new Zend_Form_Element_Password('password');
        $password->setRequired(true);
        $password->setLabel("Password");
        
        $submit = new Zend_Form_Element_Submit('submit');
        $submit->setLabel('Register');
        
        $this->addElements(array($name, $email, $password, $submit));
        
        //!IMPORTANT: Add decorators after addElements()
        $this->addDecorator('FormElements'); //This add the form elements first
        $this->addDecorator('Form'); //This removes <dt> and adds the form around the <ul>
        
        //Time to remove the <dt> and add the <li>
        $this->setElementDecorators(array(
            array('ViewHelper'), //This is important otherwise you won't see your <input> elements
            array('Label'),  //We want the label
            array('Errors') , //We want the errors too
        ));

        /* Submit elements don't need a label since we added a label on setElementDecorators()
           on <input> elements (including the submit) */
        $submit->setDecorators(array('ViewHelper'));
    }
}

?>

 

This is what our markup now looks like:

Zend form with decorators markup

 

As you can see the form now looks clean but if you take a look at how it looks its still not right displayed in one line like that. We will now style our form by wrapping our form elements inside <li> tags. We also won't be just echoing the form on the view. Instead we will get each element on the form object that's passed to the view. These elements are objects themselves (inside our form object. OOP) so we can echo them individually. This way we take advantage of the framework's built in validatio we have set on our form object but still have the freedom to style the form however we want. It's more like adapting our form to our design. So lets modify our view by adding css styling to it. This is how our index.phtml file look like:

<html>
    <head>
        <style type="text/css">
            ul {
                width: 550px;
                font-family: Arial;
                -webkit-box-shadow: 0 0px 5px #ddd;
                -moz-box-shadow: 0 0px 5px #ddd;
                box-shadow: 0 0px 5px #ddd;
                border: 1px solid #ccc;
                margin: 100px;
                padding: 0;
                float: left;
            }
            
            ul li.title {
                background: #0080C0;
                color: #fff;
            }
            
            ul li {
                list-style: none;
                padding: 10px;
                float: left;
                width: 96.5%;
            }
            
            ul li input[type="text"], ul li input[type="password"] {
                border: 1px solid rgb(182, 182, 182);
                box-shadow: 0px 0px 3px rgba(0, 0, 0, 0.15);
                width: 82%;
                float: left;
                padding: 4px;
            }
            
            ul li input[type="submit"] {
                background: -moz-linear-gradient(top, #0079be, #00688f);
                background: -o-linear-gradient(top, #0079be, #00688f);
                background: -webkit-linear-gradient(top, #0079be, #00688f);
                background: -webkit-gradient(linear, left top, left bottom, from(#0079be), to(#00688f));
                background: -ms-linear-gradient(top, #0079be, #00688f);
                background: linear-gradient(top, #0079be, #00688f);
                background: #0079be;
                color: #fff;
                padding: 10px 20px 10px 20px;
                float: right;
                margin: 0px 10px 8px;
                font-size: 12px;
                font-weight: bold;
                border: none;
                border-radius: 3px;
                -webkit-border-radius: 3px;
                -moz-border-radius: 3px;
                box-shadow: 0px 0px 4px #039cd5 inset !important;
                -webkit-box-shadow: 0px 0px 4px #039cd5 inset !important;
                -moz-box-shadow: 0px 0px 4px #039cd5 inset !important;
            }
            
            ul li label {
                width: 14% !important;
                font-size: 12px;
                float: left;
            }
            
            /** This is for the errors */
            ul li ul {
                width: 100%;
                font-family: Arial;
                font-size: 11px;
                -webkit-box-shadow: none;
                -moz-box-shadow: none;
                box-shadow: none;
                border: none;
                margin: 0;
                padding: 0;
                float: left;
            }
            
            ul li ul li {
                text-align: right;
                padding: 0;
                color: red;
                font-weight: bold;
            }
        </style>
    </head>
    <body>
        <form enctype="application/x-www-form-urlencoded" action="" method="post">
            <ul>
                <li class="title">Registration form</li>
                <li><?= $this->form->name ?></li>
                <li><?= $this->form->email ?></li>
                <li><?= $this->form->password ?></li>
                <li><?= $this->form->submit ?></li>
            </ul>
        </form>
    </body>
</html>

 

As you can see, we used the form object that was passed to the view to get each element that we defined on our RegisterForm.php and echoed them out individually. See best of both worlds. The form looks like this:

The result

 

That's a wrap

There we go. Now you know how to build good looking flexible forms in Zend. Happy coding

Comments