Archive for the ‘articles’ Category

Using Zend_Form without Zend Framework MVC

Tibo BeijenMonday, December 7th, 2009
using-zend_form-without-zend-framework-mvc

Most components of Zend Framework can be used without using the entire framework and Zend_Form is no exception. It’s a versatile component that can be customized to great extent. The payoff is that seemingly easy tasks can seem quite complex to complete and involve concepts like Decorators and View Helpers. Complexity is increased by the fact that most tasks can be achieved in multiple ways.

Forms in general are elements where a lot of parts of an application ‘meet’: Frontend code (HTML/CSS), behavior (JS) and backend processing (validation, filtering and storage). In this post I’ll show how one can:

  • Use Zend_Form outside the Zend Framework MVC (most likely an existing project)
  • Separate Form rendering from it’s structure
  • Use custom validators and decorators

The Form used in this tutorial can be viewed here. The code can be browsed or downloaded on GitHub.

Zend_Form components at a glance

Let’s start with a quick look at how Zend_Form’s different components are tied together:

  • A Zend_Form consists of elements, descendants of Zend_Form_Element
  • Elements can be supplied with Validators and Filters
  • Both the form and it’s elements depend on Decorators to generate HTML. Decorators form a ‘chain’ where each decorator adds HTML to the result of the previous decorators.
  • The standard decorators provided by Zend_Form delegate the rendering of the actual HTML to View Helpers

Using Zend_Form without the MVC

As the last point above shows, Zend_Form, through Decorators, makes extensive use of Zend_View helpers. In a Zend_Framework project Zend_Form is able to retrieve the View itself. In other projects (if one wants to use any of Zend_Form’s default decorators) a View instance has to be supplied to Zend_Form:

$view = new Zend_View();
$view->doctype('XHTML1_TRANSITIONAL');
 
$form = new Zend_Form();
$form->setView(new Zend_View());

In this example the doctype is specified in the view. This controls if input elements are rendered with XHTML self-closing tags.

Separate structure and rendering

In this tutorial I create a form for an admin interface where basic user-details can be edited. Let’s assume an ACL implementation dictates that some people can actually edit the details while others are only allowed to view them. I’ve decided to keep the form definition (the ‘model’ side of a form) to a bare minimum and let different renderers (the ‘view’ side) control the output.

For re-usability and keeping controller code clean one can best create form objects by creating an instance of a subclass of Zend_Form:

class My_Form_User extends Zend_Form
{
    public function init() {
        // username
        $this->addElement('text','username', array(
            'required' => true,
            'validators' => array(
                // arguments: type, breakchain, validator constructor options
                array('Alnum', false, false),
                array('StringLength', false, array(6, 16)),
            ),
        ));
 
        // email
        $EmailValidate = new My_Validator_Email();
        $this->addElement('text','email', array(
            'required' => true,
            'validators' => array(
                array('EmailAddress', false),
                array($EmailValidate, false)
            )
        ));
 
        // ...
    }
}

(As can be seen I create an instance of My_Validate_Email and add that to the email element. We’ll look into that later. First, let’s continue with the form definition.)

The init() method is designed for this type of form definition, thereby avoiding the need to duplicate the constructor and it’s parameter scheme. As can be seen, I only define the form elements and validators. Labels and such I defer to the renderer (more on that later). As this is about integrating Zend_Form into existing projects that are not based on Zend Framework, I assume there is some sort of language-aware component. In this example I use a language pack that returns language-specific results based on tags. Adding a set of checkboxes then looks like this:

class My_Form_User extends Zend_Form
{
    public function init() {
 
        // ...
 
        $lang = new My_LanguagePack();
 
        $groupIds = array(1,2,3,4);
        $groupOptions = array();
        foreach ($groupIds as $id) {
            $groupOptions[$id] = $lang->get('group.label.' . $id);
        }
 
        $elmGroup = new Zend_Form_Element_MultiCheckbox('group');
        $elmGroup->setMultiOptions( $groupOptions );
        $elmGroup->setRequired(true);
        $this->addElement($elmGroup);
    }
}

Now I create two renderer classes for both the ‘edit’ and ‘view’ display mode. Both accepting a Zend_Form instance in the constructor. Code below shows how the form is displayed using either rendering class:

$Form = new My_Form_User();
 
$RendererEdit = new My_Form_Renderer_Edit($Form, 'user_edit');
echo $RendererEdit->render();
 
$RendererView = new My_Form_Renderer_View($Form, 'user_view');
echo $RendererView->render();

But before moving onto the renderers, let’s look into the aforementioned My_Email_Validator class.

Adding a custom validator

When specifying validators by string, as is done with ‘EmailAddress’, Zend_Form adds one of the types of Zend_Validate. For validation not covered by the standard validators one can create a custom validator by extending Zend_Validate_Abstract or implementing Zend_Validator_Interface. For email addresses, a typical scenario would be a custom validator that connects to a database and checks if the given email address is allready used by another user. For this demo I skip the database part, resulting in:

class My_Validator_Email extends Zend_Validate_Abstract
{
    protected $isValid = null;
 
    public function isValid($value) {
        $this->isValid = !in_array($value, array(
            'duplicate@test.com',
        ));
        return $this->isValid;
    }
 
    public function getMessages() {
        if ($this->isValid === false) {
            return array(
                'duplicateEmail' => 'This email address is allready used'
            );
        }
        return array();
    }
 
    public function getErrors() {
        return array_keys($this->getMessages());
    }
}

Now let’s continue with the two renderer classes:

Rendering the edit mode

The basics of the My_Form_Renderer_Edit class constructor are shown below:

class My_Form_Renderer_Edit
{
    protected $form;
 
    protected $lang;
 
    public function __construct(Zend_Form $form, $form_id = null)
    {
        $view = new Zend_View();
        $view->doctype('XHTML1_TRANSITIONAL');
 
        $this->form = $form;
        $this->form->setView(new Zend_View());
        $this->form->setAttrib('class', 'form_edit');
        if (!is_null($form_id)) {
            $this->form->setAttrib('id', $form_id);
        }
 
        $this->lang = new My_LanguagePack();
    }
 
    public function render()
    {
        // ...
}

As can be seen this is where I setup the view (as mentioned before) and set id and classname that can be used in CSS. I want the HTML to look like this:

<ul>
    <li class="">
        <div id="username-label"><label for="username" class="required">* Username</label></div>
        <div class="element">
            <input type="text" name="username" id="username" value="" class="text" />
            <span class="description">(Min 6, max 16 char.)</span>
        </div>
    </li>
</ul>

When the render() method is called on the renderer class I do four things:

  • Add a submit element
  • Setup element properties that are common for all elements
  • Setup properties on a per-element basis
  • Setup properties of the form element

I’ll briefly run through those steps. Complete code for My_Form_Renderer_Edit can be seen on Github.

Add a submit element

As long as the submit value doesn’t play a role in the processing of entered data I consider this part of the view layer. For example, interaction design might dictate that on long forms submit buttons are placed both above and below the form.

Setup common properties

By using the method setElementDecorators() of Zend_Form, all default decorators are replaced by the ones specified. The decorators that fit my needs are ViewHelper (renders the element itself) and Description, resulting in:

    protected function setupElementsCommon()
    {
         $this->form->setElementDecorators(array(
            'ViewHelper',
            array('Description', array(
                'placement' => 'append',
                'tag' => 'span',
                'class' => 'description'
            )),
         ));
    }

Setup per-element properties

Here I add additional decorators. First I setup the element’s label and description properties by using the language pack, then I add the appropriate decorators. Furthermore I add some additional classnames to elements. If the element has an error I not only want to display the errors (using a custom decorator, more on that later). I also want to give the HTML element wrapped around all of the parts an ‘error’ classname.

        $elmHasError = (count($elm->getMessages()) > 0);
        $liClass = $elmHasError ? 'error' : '';
        $elm->addDecorator(
            array('outerLi' => 'HtmlTag'),
            array('tag' => 'li', 'class' => $liClass)
        );

Setup the form object

Finally the Form is configured. After removing all existing decorators, three decorators are added. The only difference with the default set of decorators is the UL element used in the HtmlTag decorator:

    protected function setupForm()
    {
        $this->form->clearDecorators();
        $this->form->addDecorator('FormElements');
        $this->form->addDecorator('HtmlTag', array('tag' => 'ul'));
        $this->form->addDecorator('Form');
    }

Adding a custom decorator

The complete code shows that instead of the default ‘Errors’ decorator I provide my own. This way I can retrieve the error messages provided by the form element and then replace them with messages retrieved from the languagePack. A custom decorator needs to extend Zend_Form_Decorator_Abstract or implement Zend_Form_Decorator_Interface. Excerpts from My_Decorator_Errors:

    public function render($content)
        $element = $this->getElement();
        $errorMessages = $element->getMessages();
        if (empty($errorMessages)) {
            return $content;
        }
 
        // iterate over errorMessages, replace or use default
        $errorLinesHtml = '';
        foreach ($errorMessages as $errorCode => $errorMsg) {
            // make an exception for isEmpty and array representing elements
            if ($element->isArray() && $errorCode=='isEmpty') {
                $msgLangPack = $this->lang->get('form.error.array.' . $errorCode);
            } else {
                $msgLangPack = $this->lang->get('form.error.' . $errorCode);
            }
            $errorMsg = ($msgLangPack !== false) ? $msgLangPack : $errorMsg;
            $errorLinesHtml .= '<li>' . $errorMsg . '</li>';
        }
        // combine
        $errorHtml = '<ul class="errors">' . $errorLinesHtml .'</ul>';
 
        // ...

Errormessages are fetched by an element’s getMessages() method that returns an associative array. The error-codes (keys) can be used to translate the message. As can be seen I treat elements representing an array differently when fetching the ‘isEmpty’ error message.

Why using a custom errors decorator and not setting the messages on the element?

setErrors() can be used to set own errors on Zend_Form_Element. Those errors are stored in property _errorMessages which is indeed cleared first. This doesn’t remove the messages received from the validators though as they are stored in _messages. Upon adding an error by setErrors() both arrays are merged into _messages (this happens in markAsError()) and that’s the one returned by getMessages(). So trying to replace the existing isEmpty error by ’setting’ a custom error effectively adds an error instead of replacing it. getErrorMessages() does return just the new errors but… the viewHelper formErrors (which is invoked by the default ‘Errors’ decorator) uses getMessages()…

Rendering the view mode

The view renderer is a simplified version of the edit renderer. Main differences are:

  • The form doesn’t have a Form decorator and thereby no form tag. (I’ll keep calling the no-form a form though ;)).
  • All elements have only one decorator common for all elements: My_Decorator_View_Element
  • As the only element decorator doesn’t use Zend_View, the form has no need for a View element.

My_Decorator_View_Element

This decorator retrieves value and label from the element and creates. It then creates HTML making exceptions for:

  • Submit elements (which are ignored)
  • Array representing elements (where more than one value needs to be displayed)

Concluding

Above examples give an impression of how Zend_Form can be suited to virtually anyone’s needs. One can argue that separating the rendering from the basic definition adds unnecessary complexity. It does however pull HTML specifics (which during a project life-cycle often are subject to change) out of the ‘model’ layer. Both the stripped down forms and renderers are easy to reuse: The renderer can be applied to a number of forms and the forms themselves can be used in projects requiring different HTML.

Even without considering the rendering part, Zend_Form is a valuable platform offering a lot of ways to customize it. As the view renderer example shows it can also operate without Zend_View, provided one doesn’t use any of the built in decorators. Being able to provide self-built elements, validators and decorators makes it possible to use Zend_Form in virtually any project.

Further reading:

Catching PHP Exceptions: Except the unexpected

Tibo BeijenMonday, October 26th, 2009
catching-php-exceptions-except-the-unexpected

PHP Exceptions can greatly assist in implementing various error scenario’s into an application. Before PHP5 one had to resort to specific return values or drastic measures like trigger_error(). Planning exceptions, I found out, is just as important as class design. At any point where a developer needs to handle the possibility of an exception being thrown he needs to know:

  • What Exceptions can I expect?
  • What Exceptions do I plan to catch?

In this post I’ll show some important aspects to consider when planning exceptions.
(more…)

Usability: What does this button do?

Tibo BeijenFriday, October 9th, 2009
usability-what-does-this-button-do

In software development projects, paying proper attention to usability aspects, can greatly help ‘getting the message functionality across’. Usability is a field of expertise on its own and involves techniques like wireframes, prototyping and card sorting. Not every project is the same and (sadly) lack of time or budget can prevent specialized interaction designers to be involved in the project. This means that making the application ‘usable’ becomes the responsibility of graphic designers or developers (or it is neglected altogether). Not an easy combination of tasks…
(more…)

Controlled initialization of domain objects

Tibo BeijenThursday, July 9th, 2009
controlled-initialization-of-domain-objects

In a recent project I’ve been working on, we have used the ‘Domain Model‘ to describe and design our application. Doing so we decouple persistency logic from the objects that are being passed around and modified throughout our application: The Domain objects. So what in MVC is often referred to as ‘model’ is actually a combination of a persistency layer, a service layer and a Domain layer. The persistency and service layer are also referred to as Data Access Objects: DAO. (As for the why and how of this architecture I recommend the article Writing robust backends with Zend Framework. For a good description of the DAO concept look here).

One of the challenges we were facing was that on one hand we wanted to implement business rules in our Domain objects. In plainish english: On setting or changing properties of the object (like changing a status) we want to validate if that action is allowed. On the other hand we want to be able to initialize an object to whatever state corresponds with the data fetched from the persistency layer. Doing so we found that the business rules got in the way during initialization when fetching it from the persistency layer. So what we were looking for was a way to allow the service layer to construct a Domain object using methods that are hidden from the rest of the code. We found two ways:

  1. Reflection (as of PHP 5.3)
  2. A design pattern where the Domain object initializes itself using the provided Service object.

(more…)

Explicit PHP6?

Tibo BeijenThursday, June 11th, 2009
explicit-php6

Some days ago I read Fabien Potencier’s post ‘What for PHP 6′ pointing me to some features that might be implemented in PHP6. Two of those would have been nice in a project I’m currently working on where I’ve been experimenting with ‘domain objects’ having ’scalar’ or ‘value’ objects as properties (more on that later). The first is scalar type hinting and hinted return values. The other is a __cast() method that replaces (or complements __toString()). Now that sounds quite java-ish and one of PHP merits is it’s flexibility but having the option to be more strict in my opinion is a good thing: If I feed my application with garbage I don’t blame it for being equally blunt.
(more…)

Web Browser Zoom: Design consequences

Tibo BeijenSaturday, March 7th, 2009
web-browser-zoom-design-consequences

Over the years the display size of the average computer screen has increased. As a consequence nowadays more and more websites are designed with a 1024 width screen in mind. For example: BBC, Adobe and The New York Times. With at least 78% of the users using a 1024 or higher resolution screen the time seems right to move away from the 800px designs. But what about accessibility? And usability? And is full page zooming really better than text scaling?
(more…)

Thousands of modules can’t be wrong, right?

Tibo BeijenFriday, February 20th, 2009
thousands-of-modules-cant-be-wrong-right

Yesterday I attended a presentation showcasing Drupal. Like Joomla! and Wordpress an easy install routine presents the user with a lot of functionality right out of the box. By adding modules as needed one can achieve whatever he wants. So it seems… After the showcase part, the session continued into a case study. The case at hand was a project were all sorts of specific functionality (think: facebook, digg, etc. web 2.0 you know) was required. And it didn’t go as smooth and quick as expected. How come?
(more…)

Zend_Config strategies

Tibo BeijenSunday, November 30th, 2008
zend_config-strategies

As applications often need to run on different setups (think: develop, test, production), configuration settings can usually be divided in a static ‘application’ part and a more dynamic ‘environment’ part. Zend Framework offers a very flexible set of classes that help reading and organizing configuration data and making it available throughout the entire application. But, as very often, there is no ‘only way’.

(more…)

Enterprise iPhone Applications: First steps

Tibo BeijenMonday, November 17th, 2008
enterprise-iphone-applications-first-steps

The iPhone is a very popular gadget and this popularity is not limited to long-time and die-hard Mac fan’s. Enterprises also seem triggered by the iPhone’s slick appeal, if only because an increasing number of employees has the flashy device lying near them on the conference table. (Or the lunch table for that matter).

So what are a company’s options if it want to have it’s own shiny icon at the iPhone home screen? Does the ease of use extend beyond the user-interface? In this guide, doomed to be aged in mere months, I’ll outline the options one has for developing enterprise software for the iPhone.

(more…)