The Contact Page: The Contact Form
Saturday, November 7, 2009

Although the example website currently only has one form, the contact form, other forms may be added to it in the future; therefore, in implementing the form, I created an abstract base class for site forms, which contains the functionality shared by all forms.

The abstract class is called Default_Form_Abstract and is stored in the application/forms directory. It is derived from Zend Form.

The skeleton abstract class declaration is as follows:

<?php
abstract class Default_Form_Abstract extends Zend_Form
{
  // The class methods and variables are declared here.
}

The Zend_Form module uses the decorator pattern to define the markup used to render a form. The base form class uses decorators to render the forms as tables. The decorators used to render the form fields are contained in the following two variables:

  private $_fieldDecorators = array(
    'ViewHelper',
    array(array('data' => 'HtmlTag'), 
array('tag' => 'td', 'class' => 'element')),
    array('Label', array('tag' => 'td')),
    array(array('row' => 'HtmlTag'), 
array('tag' => 'tr'))
  );
 
  private $_buttonDecorators = array(
    'ViewHelper',
    array(array('data' => 'HtmlTag'), 
array('tag' => 'td', 'class' => 'element')),
    array(array('label' => 'HtmlTag'), 
array('tag' => 'td', 'placement' => 'prepend')),
    array(array('row' => 'HtmlTag'), 
array('tag' => 'tr'))
  );

These decorators are applied to field elements declared in derived classes using the following two methods. The first is used for most fields, which have labels; the second is used for buttons such as the submit button, which don’t have a label:

  public function setFieldDecorators($field)
  {
    $field->setDecorators($this->_fieldDecorators);
  }
 
  public function setButtonDecorators($button)
  {
    $button->setDecorators($this->_buttonDecorators);
  }

The overall styling for the form is set in the init method:

  public function init()
  {
    // Set the form decorators
    $this->setDecorators(
      array(
        'FormElements',
        array('HtmlTag', array('tag' => 'table')),
        'Form'
      )
    );
  }

Finally, there is a method used to retrieve the first error message generated by a failed validation:

  public function getFirstFormError()
  {
    $fields = $this->getMessages();
 
    foreach ($fields as $field => $messages)
    {
      foreach ($messages as $message)
      {
        $error = array('message' => $message, 'field' => $field);
        return $error;
      }
    }
 
    return null;
  }

This method is necessary as normally details of all fields that have failed validation are returned, but the usual (and my preferred) practice is to only report the first field that has failed validation. This has always struck me as less confusing for the user.

The abstract class is called Default_Form_Abstract and is stored in the application/forms directory. It is derived from Zend Form.

The skeleton abstract class declaration is as follows:

<?php
class Default_Form_Contact extends Default_Form_Abstract
{
  public function init()
  {
    // The code used to initialise the form is inserted here.
  }
}

The init method starts by calling the init method of the parent class:

    parent::init();

This is essential as the parent method sets up the form decorators.

Next the method sets the form ID:

    // Set the form ID
    $this->setAttrib('id', 'contact_form');

Then the method sets the form submission method to POST:

    // Submit the form using a POST request
    $this->setMethod('post');

The first form element is the Name field, which is a normal text field.

The script first creates an appropriate form element:

    // Name field
    $name = new Zend_Form_Element_Text('name',
      array(
        'label'      => 'Your name:', 
        'required'    => true, 
        'filters'    => array('StringTrim'),
        'maxlength'    => 64
      )
    );

The first parameter is the field name/id.

The second parameter is an array of additional settings. Here these are:

  • label: This specifies the label attached to the field.
  • required: This specifies whether the field is required; in this case it is, so the field will fail validation if it is not.
  • filters: This specifies the filters to apply to the field; in this case, it is the trim filter, used to remove leading and trailing space.
  • maxlength: This specifies the maximum length of the data than can be entered in the field.

The script then adds the error message to display, if the field fails validation:

    $name->setErrorMessages(array('Please enter your name.'));

The script then adds the appropriate decorators to the field, to ensure that it is rendered as a table row:

    $this->setFieldDecorators($name);

Finally the field is added to the form:

    $this->addElement($name);

A similar process is followed for the other form fields:

    // E-mail field
    $email = new Zend_Form_Element_Text('email', 
      array(
        'label'      => 'Your e-mail address:', 
        'required'    => true, 
        'filters'    => array('StringTrim'), 
        'validators'  => array('EmailAddress'),
        'maxlength'    => 255
      )
    );
    $email->setErrorMessages(
array('Please enter a valid e-mail address.'));
    $this->setFieldDecorators($email);
    $this->addElement($email);
 
    // Message field
    $message = new Zend_Form_Element_Textarea('message', 
      array(
        'label'     => 'Your message:',
        'required'  => true,
        'rows'      => 6,
        'cols'      => 50
      )
    );
    $message->setErrorMessages(array('Please enter a message.'));
    $this->setFieldDecorators($message);
    $this->addElement($message);
 
    // Submit button
    $submit = new Zend_Form_Element_Submit('submit', 
      array(
        'ignore'    => true, 
        'label'     => 'Send',
        'class'     => 'ui-state-default ui-corner-all'
      )
    );
    $this->setButtonDecorators($submit);
    $this->addElement($submit);

The e-mail field has a specific validator applied to it, rather than the general required setting.

The text area has its rows and columns set, rather than a maxlength.

Note that the submit button has different decorators applied to it, as unlike the other fields, it does not have a label.

In my next most, I shall finish my coverage of the contact page by looking at the class used to send the contact e-mail.

Posted by James at 5:49 pm   0 comments

Leave a Reply