Form Creation in Zend Framework 2

There are several different ways to go about Form Creation in Zend Framework 2. This article will focus on extending the Form class and using a form in the ZF2 Skeleton Application.

Assuming you have already created a basic module, you should be ready to start creating a form.

To start with, create a Form/ directory in module/[Your_Module]/src/[Your_Module]. Usually the class name given will be related to the type of form you’re looking to build.

In this example, a simple register form will be built.

The form class must extend Zend\Form\Form and any elements added to the form must be added within the class’ __construct() method.

// module/Siphor/src/Siphor/Form/RegisterForm.php
<?php
namespace Siphor\Form;

use Zend\Form\Form;

class RegisterForm extends Form {

    public function __construct($name = 'register')
    {
        parent::__construct($name);

        $this->setAttribute('method', 'post');
    }
}

Form elements can be added using the add() method of the Zend\Form\Form class.

// module/Siphor/src/Siphor/Form/RegisterForm.php
<?php
namespace Siphor\Form;

use Zend\Form\Form;

class RegisterForm extends Form {

    public function __construct($name = 'register')
    {
        parent::__construct($name);

        $this->setAttribute('method', 'post');

        $this->add(array(
            'name' => 'first_name',
            'type' => 'Zend\Form\Element\Text',
            'options' => array(
                'label' => 'First Name'
            ),
            'attributes' => array(
                'type' => 'text',
                'required' => true
            )
        ));

        $this->add(array(
            'name' => 'last_name',
            'type' => 'Zend\Form\Element\Text',
            'options' => array(
                'label' => 'Last Name'
            ),
            'attributes' => array(
                'type' => 'text',
                'required' => true
            )
        ));
    }
}

ZF2 uses its own classes for input types i.e. Zend\Form\Element\Text. There is also a Zend\Form\Element\Email class to use with email inputs.

$this->add(array(
    'name' => 'email',
    'type' => 'Zend\Form\Element\Email',
    'options' => array(
        'label' => 'Email Address'
    ),
    'attributes' => array(
        'type' => 'email',
        'required' => true
    )
));

Use the Zend\Form\Element\Password class for password fields. Usually with register forms, a password and a password confirmation field are present.

$this->add(array(
    'name' => 'password',
    'type' => 'Zend\Form\Element\Password',
    'options' => array(
        'label' => 'Password'
    ),
    'attributes' => array(
        'type' => 'password',
        'required' => true
    )
));

$this->add(array(
    'name' => 'password_verify',
    'type' => 'Zend\Form\Element\Password',
    'options' => array(
        'label' => 'Confirm Password'
    ),
    'attributes' => array(
        'type' => 'password',
        'required' => true
    )
));

Web forms can be susceptible to cross-site request forgery (csrf) attacks. Fortunately, Zend Framework provides us with a Zend\Form\Element\Csrf to use in our forms.

$this->add(array(
    'name' => 'csrf',
    'type' => 'Zend\Form\Element\Csrf'
));

Lastly, a submit button is required in order for users to be able to submit the form.

$this->add(array(
    'name' => 'submit',
    'type' => 'Zend\Form\Element\Submit',
    'attributes' => array(
        'value' => 'Submit'
    )
));

The complete form class might look like the following:

// module/Siphor/src/Siphor/Form/RegisterForm.php
<?php
namespace Siphor\Form;

use Zend\Form\Form;

class RegisterForm extends Form {

    public function __construct($name = 'register')
    {
        parent::__construct($name);

        $this->setAttribute('method', 'post');

        $this->add(array(
            'name' => 'first_name',
            'type' => 'Zend\Form\Element\Text',
            'options' => array(
                'label' => 'First Name'
            ),
            'attributes' => array(
                'type' => 'text',
                'required' => true
            )
        ));

        $this->add(array(
            'name' => 'last_name',
            'type' => 'Zend\Form\Element\Text',
            'options' => array(
                'label' => 'Last Name'
            ),
            'attributes' => array(
                'type' => 'text',
                'required' => true
            )
        ));

        $this->add(array(
            'name' => 'email',
            'type' => 'Zend\Form\Element\Email',
            'options' => array(
                'label' => 'Email Address'
            ),
            'attributes' => array(
                'type' => 'email',
                'required' => true
            )
        ));

        $this->add(array(
            'name' => 'password',
            'type' => 'Zend\Form\Element\Password',
            'options' => array(
                'label' => 'Password'
            ),
            'attributes' => array(
                'type' => 'password',
                'required' => true
            )
        ));

        $this->add(array(
            'name' => 'password_verify',
            'type' => 'Zend\Form\Element\Password',
            'options' => array(
                'label' => 'Confirm Password'
            ),
            'attributes' => array(
                'type' => 'password',
                'required' => true
            )
        ));

        $this->add(array(
            'name' => 'csrf',
            'type' => 'Zend\Form\Element\Csrf'
        ));

        $this->add(array(
            'name' => 'submit',
            'type' => 'Zend\Form\Element\Submit',
            'attributes' => array(
                'value' => 'Submit'
            )
        ));

    }
}

Within the IndexController class, import your form class using the ‘use’ keyword.

use Siphor\Form\RegisterForm;

You can then pass the class instance to an array when returning a new ViewModel instance.

// module/Siphor/src/Siphor/Controller/IndexController.php
<?php
namespace Siphor\Controller;

use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Siphor\Form\RegisterForm;

class IndexController extends AbstractActionController
{
    public function indexAction()
    {
        $registerForm = new RegisterForm();
        return new ViewModel(array('form' => $registerForm));
    }
}

In the view template, the form can be accessed using $this->form as the ‘form’ key was defined in the array when instantiating a new ViewModel class.

To render the form opening and closing tags, the form view helper, $this->form() is used (not to be confused with $this->form).

// module/Siphor/view/siphor/index/index.phtml
<?php
$this->form->setAttribute('class', 'form-horizontal');
$this->form->prepare();
echo $this->form()->openTag($this->form);
echo '<fieldset>';

foreach ($this->form as $element) {
    if (!($element instanceof Zend\Form\Element\Submit)) {
?>
        <div class="control-group">
            <label class="control-label" for="<?php echo $element->getName(); ?>"><?php echo $this->translate($element->getLabel()); ?></label>
            <div class="controls">
                <?php echo $this->formElement($element); ?>
                <?php echo $this->formElementErrors($element); ?>
            </div>
        </div>
<?php
    } else {
        $element->setAttribute('class', 'btn btn-primary');
?>
        <div class="form-actions">
            <?php echo $this->formElement($element); ?>
        </div>
<?php
    }
}
echo '</fieldset>';
echo $this->form()->closeTag();

When you refresh your application, you should see the form rendered on your designated module’s URL.

Form Creation in Zend Framework 2

Currently the form doesn’t go anywhere, nor does it have any validation. Using the Input Filter will be covered in another post.

Note: This article is based on ZF version 2.4.