DDD using Doctrine 2: A case study

Tibo BeijenJune 27th, 2011
ddd-using-doctrine-2-a-case-study

Nowadays developing web applications usually requires a flexible process due to changing business logic, shifting priorities or new insights. Besides choosing the right methodology this also requires designing the application in such a way that this flexibility can be achieved.

Domain Driven Design fits this process as it isolates business logic in the Domain layer and separates it from infrastructure and presentation layers. Questions like where or how to store data or what to build (website, mobile app, API) can be addressed separately.

Doctrine 2 provides PHP developers with a powerful tool to create a Domain layer that contains business logic that is easy to unit test and therefore easy to expand upon in iterations.

In this article I will show how to implement a specific case using Doctrine 2. Full code accompanying this article can be found on GitHub.
more…

  • Twitter
  • LinkedIn
  • Facebook
  • StumbleUpon
  • DZone

DPC 2011 preview

Tibo BeijenMay 17th, 2011
dpc-2011-preview

The yearly dutch PHP event is getting close so time to check out the schedule. Once again there are lots of interesting sessions to choose from so I probably will miss some of the good stuff. Mixing ‘simply interesting’ and ‘directly usable in day-to-day job’ results in the preliminary list:

Day 1

Day 2

  • Pofiling, OAuth, new era of PHP Frameworks – All interesting, to be decided
  • Managing a shared MySQL farm – Because I expect to hear more new things than at the Zend Framework optimization talk
  • Agility and Quality, Modular application architecture and Character sets that suck (they do!) – Tough one once again. I think Agility and Quality
  • Practical Git – I think, because there’s a lot to learn there, although Zend Framework i18n looks interesting too
  • Keynote: Open Teams – Will probably be insightful as well as enjoyable

Now I only need to print the ticket, bookmark this page on my iPhone and I’m off to go. Till friday!

  • Twitter
  • LinkedIn
  • Facebook
  • StumbleUpon
  • DZone

Usability: Autofocus and not breaking the backspace-button

Tibo BeijenMarch 14th, 2011
usability-autofocus-and-not-breaking-the-backspace-button

A while ago during a project we were asked to implement autofocus on the generic search field that every page in the application has. At a first glance a pretty straightforward task, from a technical perspective that is. Not from a user perspective, as indicated by a colleague mentioning his dislike of such autofocus fields “because they prevent backspace going to the previous page”. In this post I will outline some usability considerations and conclude with a jQuery plugin that will take away some of the possible hindrance of autofocusing a field.

Usability considerations

There are some things to consider to determine if such automatic focusing of a search field is actually helpful to the user navigating to the page. Who is the user?

As I was discussing this case with an interaction designer friend (dutch) of mine, he brought up the idea of mimicking the browser’s backspace behaviour, and discussing it further we concluded that this might be useful in some cases but is definitely not a ‘one size fits all’ solution.

Different goals

Different users will probably have different goals when navigating to a page. On the google page or a login screen the majority of the users’ goal is to type something in the first input field. On a lot of other pages this won’t be so obvious. Question then is: Will focusing a search field, if not help, instead hinder the user? For example: A user might have navigated to a page by accident. In that case not being able to go to the previous page by pressing ‘backspace’ might indeed hinder the user.

Different expectations

Not every user navigates to the previous page by using ‘backspace’, some might not even be aware of that possibility. Not every user expects text entered to automatically appear in an input field. Some users might have enabled the option to directly find text in a page when typing text and find this functionality suddenly broken.

Dive into HTML5 has some other nice examples of how autofocus might not be helpful.

What size fits all?

As mentioned before, there is no ‘one size fits all’ solution. Questions that need to be asked include:

  • How many users might be helped by adding autofocus to a common search field?
  • How many users might instead be hindered by autofocus?
  • Are there pages where autofocus on more specific fields (like the main form) is needed which will break consistency throughout the site?

This means studying your site, the target audience, their goals and expectations and based on that finding a balance.

Restoring the backspace: jQuery autofocusBackspace plugin

If the conclusion of aforementioned considerations is that autofocus indeed is helpful, there is more than one way to achieve this: The first is using the HTML5 autofocus attribute. Another is using javascript to focus the field.

As not all browsers support the autofocus attribute yet, and we wanted to preserve the browser’s backspace functionality, I created a jQuery plugin that does just that:

  • It focuses the first matching element
  • It responds to ‘backspace’ by navigating to the previous page.
    • Only until a user has entered text
    • Only until the element loses focus

Refer to GitHub for the jQuery plugin autospaceBackspace.

Feel free to report problems or ideas for improvement.

  • Twitter
  • LinkedIn
  • Facebook
  • StumbleUpon
  • DZone

Fixing mysqldump on Zend Server CE on OS X

Tibo BeijenMarch 1st, 2011
fixing-mysqldump-on-zend-server-ce-on-os-x

A while ago I installed Zend Server Community Edition on OS X which was pretty straightforward. It was only recently that I found out that, as opposed to mysql which worked fine, mysqldump didn’t work correctly and terminated with the error:

mysqldump: Got error: 2002: Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2) when trying to connect

Inspecting the mysql configuration contained in /usr/local/zend/mysql/data/my.cnf confirmed that the section [client] showed the socket as returned by executing SHOW VARIABLES; from the mysql client: /usr/local/zend/mysql/tmp/mysql.sock

Although it is possible to specify the socket by using mysqldump’s --socket switch, that doesn’t really seem a ‘solution’.

Apparently mysqldump, as opposed to the mysql client does not use the server-specific settings contained in /usr/local/zend/mysql/data/my.cnf. The comments in my.cnf state:

# You can copy this file to
# /etc/my.cnf to set global options,
# mysql-data-dir/my.cnf to set server-specific options (in this
# installation this directory is /usr/local/zend/mysql/data) or
# ~/.my.cnf to set user-specific options.

After copying /usr/local/zend/mysql/data/my.cnf to /etc/my.cnf mysqldump worked as expected.

In /etc/my.cnf I have included only the setting needed to get mysqldump running:

# Specifying socket to use for mysql/mysqldump
# For other settings refer to /usr/local/zend/mysql/data/my.cnf
[client]
socket      = /usr/local/zend/mysql/tmp/mysql.sock

Hope this saves anyone running into the same issue some time.

Update (alternative solutions):
As Joel Clermont pointed out it is also possible to create a symlink on the socket location expected by mysqldump to the real socket location. This can be done by executing:

ln -s /usr/local/zend/mysql/tmp/mysql.sock /tmp/mysql.sock

Another possible approach is to create a symlink at /etc/my.cnf to /usr/local/zend/mysql/data/my.cnf. This has the downside that it requires loosening the default permissions (drwxr-x---) on the data folder by allowing ‘others’ to enter it. Commands to execute:

sudo chmod o+x /usr/local/zend/mysql/data
sudo ln -s /usr/local/zend/mysql/data/my.cnf my.cnf

Granting more permissions can be a security consideration but on most development setups this probably won’t be an issue.

Additional info about Zend Server CE on OS X:

  • Twitter
  • LinkedIn
  • Facebook
  • StumbleUpon
  • DZone

Dutch PHP Conference (DPC) 2010

Tibo BeijenJune 15th, 2010
dutch-php-conference-dpc-2010

Past weekend the Amsterdam RAI was the centre of the PHP universe as there the 2010 edition of the Dutch PHP Conference was held. Similar to past year it consisted of two presentation days, which I attended, preceded by a tutorial day.

Among the presentations I attended on the first day were:

Kevlin Henney’s keynote presentation, titled 97 Things every programmer should know. I suppose every attendant will have recognised some of the things he addressed, like “Do lots of deliberate practice” or “Hard work does not pay off”.

Design for Reusability. In this presentation Derick Rethans showed a number of concepts that can help in making code more reusable. Topics included Dependency Injection Containers, the fact that private methods can never be tested and Tie-Ins. Interesting was that Derick stated that reflection is slow whereas on day 2, in the Doctrine 2 uncon talk reflection was said to be be reasonably fast (in php 5.3 that is).

Database version control by Harrie Verveer was a very interesting talk, if only for the fact that it is a topic I’m confronted with at my day job. He showed tools like DbDeploy (and Phing), Liquibase, Doctrine Migrations and Akrabat DB Schema Manager. Especially ineresting was how branching can trouble database versioning.

Stephan Hockdoerfer’s presentation Testing untestable code showed some very unorthodox examples of how to test code that seems untestable, like replacing function names, manipulating the include path or mocking the filesystem. Interesting and besides that it’s great stuff to scare co-workers with (“look what trick I’ve learned!”).

Due to an unlucky combination of a tiresome week, a busy schedule ahead, a lot of time to kill until 20:30, and possibly age, I missed the social, so I was not devastated when day 2 started.

First presentation of day 2 was titled Security Centered Design: Exploring the Impact of Human Behaviour by Chris Shiflet. Emphasis was not on the technical aspects but on the people using an application. The presentation contained a very effective demonstration of ‘change blindness’. Quote of the presentation, and as far as I’m concerned whole DPC10: ” If you focus on the technical problem you’re missing the actual problem”

Following the keynote talk, Rob Allen covered the topic of Stress-free deployment. There was some overlap with the database versioning talk of the previous day but still a lot to learn. Especial interesting I found the part about branching, where Rob showed how branching features as well as releases can be a good solution for some pitfals concerned with release management. Not entirely in line with the branching ‘problems’ mentioned in the database versioning talk so it’s definitely a subject I’ll look into further.

After the lunch I visited the Unconference room which I didn’t regret. Jeroen Keppens opened with a short presentation on a topic we need to look into at my job in the near future: Integrating Zend_Acl and the domain layer. Short but very insightful. After two presentations about development for mobile devices (PhoneGap looks very interesting) and Cairo I decided to stay in the uncon room some more (thereby skipping the Domain NoSQL talk) as next on were two ORM-centered presentations: First Juozas Kaziukenas explained the principles of an ORM, followed by Benjamin Eberlei giving insight on Doctrine2. That looked promising yet also, after viewing the generated SQL of some of the more complex examples, spawned a very interesting discussion I had with my co-worker who visited Sebastian Bergmann’s presentation The Cake is A Lie: What problems can arise from generated code that isn’t tested and nobody is responsible for?

Concluding: Similar to past years this was a refreshing event that fuels the urge to improve by adopting new techniques and better methodologies. Besides that I really liked the Unconference initiative. Till next year!

  • Twitter
  • LinkedIn
  • Facebook
  • StumbleUpon
  • DZone

Zend_Form: Building dynamic forms

Tibo BeijenDecember 21st, 2009
zend_form-building-dynamic-forms

In my previous post about Zend_Form I showed how, using Zend_Form, a form’s structure can be separated from it’s presentation and how to use custom Decorators and Validators. The example used showed a form that is tightly coupled to a record in a database: One form edits one record. There are however numerous occasions where no ‘one to one’ connection exists and where the fields that need to be shown are not predetermined. Take for example a shopping cart that shows the amounts of each product. In this article I’ll take a look at how to:

  • dynamically construct a form based on the data being edited
  • use subforms to reuse common parts and group related values
  • create composite ‘elements’ by using the default Zend_Form_Element in combination with a custom decorator
  • create additional elements with Javascript and have them processed by the form when submitted

Like previous article the case examined assumes a situation where Zend_Form is used in an existing project that doesn’t use the Zend Framework MVC stack. The Form can be viewed online and all of the sample code can be found on GitHub.

Case outline

In this example I construct a form where a user can view and edit a task list for a week’s working days. Every task can be edited in one single form and new tasks can be added at will. When viewing the page the application fetches the tasks already entered for that week. The assumed codebase is able to generate and consume an array as shown below:

// array format used to supply data of multiple tasks to form
$tasks[$timestampDay1]['current'][$taskId1]['desc'] = 'Gotta do this';
$tasks[$timestampDay1]['current'][$taskId1]['completed'] = true;
$tasks[$timestampDay2]['current'][$taskId2]['desc'] = 'Gotta do that';
$tasks[$timestampDay2]['current'][$taskId2]['completed'] = false;

The ‘current’ part will later help to distinguish between new and allready stored tasks.

Dynamically building a Zend_Form

Using Zend_Form typically follows these steps:

$Form = new My_Form(); // My_Form::init() will define elements
$Form->setDefaults($myData);
if ($Form->isValid($_POST)) {
    $submittedValues = $Form->getValues();
    // process values and redirect to same or other page
}
echo $Form->render();

When a form’s elements need to be defined based on the data being edited, Zend_Form::init() is not suitable as at that point the data is not known yet. Providing data through the constructor to have it available in the init() method ‘could’ work but is not a really nice solution as it means changing the parameter scheme of the constructor. Furthermore, it would ignore the method that exists specifically for adding initial data: setDefaults(). As that will be the first point at which the form ‘knows’ what data needs to be edited, that will be the point to add elements. Or, as in this case, subforms.

My_Form_TaskWeek

The setDefaults() method of the week-form is changed as displayed below:

class My_Form_TaskWeek extends Zend_Form
{
    // ...
    public function setDefaults($defaults)
    {
        // first add the subforms
        $this->clearSubForms();
        $dates = array_keys($defaults);
        foreach ($dates as $day) {
            $dayForm = new My_SubForm_TaskDay();
            $this->addSubForm($dayForm, (string) $day);
        }
        // set defaults, which will propagate to newly created subforms
        parent::setDefaults($defaults);
    }
    // ...
}

For every day in $defaults (in this example the key is a timestamp, but it could be anything) a subform is added. This is done before calling parent::setDefaults(). With the subforms in place the call to the parent method will propagate to the subforms we’ve just created.

My_Form_TaskDay

In the form that shows one single day, some actions are performed in the init() method: A subform for both ‘current’ and ‘new’ elements is added. Also a ‘template’ element is added. The subforms have just one decorator: FormElements. The template element will be used as source for new elements that are added by javascript. When setDefaults() is called, elements are added to the current subform.

 class My_SubForm_TaskDay extends Zend_Form_SubForm
{
    // ...
   public function init() {
        // create subforms having nothing but element decorator
        $this->addSubForm(new Zend_Form_SubForm, 'current');
        $this->addSubForm(new Zend_Form_SubForm, 'new');
        $this->getSubForm('current')->setDecorators(array('FormElements'));
        $this->getSubForm('new')->setDecorators(array('FormElements'));
 
        // add template element
        $templateElement = $this->createTaskElement('__template__', array(), true);
        $this->getSubForm('new')->addElement($templateElement);
    }
 
    public function setDefaults($defaults)
    {
        $subform = $this->getSubForm('current');
        foreach ($defaults['current'] as $id => $values) {
            $subform->addElement($this->createTaskElement($id, $values));
        }
        // set defaults, which will propagate to newly created subforms & elements
        parent::setDefaults($defaults);
    }

The method that creates an element:

    protected function createTaskElement($id, $values, $isNew = false)
    {
        $elm = new Zend_Form_Element((string) $id);
        $elm->clearDecorators();
        $elm->addDecorator(new My_Decorator_TaskElement());
        $elm->addDecorator('Errors', array('placement'=>'prepend'));
 
        // add configured validator
        $validator = new My_Validator_TaskElement();
        $validator->setIsNew($isNew);
        $elm->addValidator($validator);
 
        return $elm;
    }

Creating composite elements by using custom decorator

As the code above shows, creating a task element consists of three steps:

Zend_Form_Element

A basic Zend_Form_Element is created. This is the ‘root’ class of which specific element-types (like Zend_Form_Element_Text) are descendants. The Form will supply each element with the element’s value which in this case will be an associative array with the keys ‘desc’ and ‘completed’.

My_Decorator_TaskElement

A custom decorator is added: My_Decorator_TaskElement. This decorator replaces what would normally be the ViewRenderer decorator. It is responsible for rendering both the text and checkbox input elements and wraps them in a div. For the template element (based on the element name) the containing div will be given a classname ‘template’ which will be of use when creating the javascript behaviour.

    public function render($content)
    {
        // get element details
        $elm = $this->getElement();
        $value = $elm->getValue();
        $elmName = $elm->getFullyQualifiedName();
 
        // construct inputs
        $isCompleted = isset($value['completed']) && $value['completed'];
        $descValue = (isset($value['desc'])) ? htmlspecialchars($value['desc']) : '';
 
        $inputDesc = sprintf(
            '<input type="text" name="%s" value="%s" />',
            $elmName . '[desc]',
            $descValue
        );
        $inputCompleted = sprintf(
            '<input type="checkbox" name="%s" value="1" %s />',
            $elmName . '[completed]',
            ($isCompleted) ? 'checked="checked"' : ''
        );
 
        // wrap in div, optionally adding attribute class
        $elmHtml = sprintf(
            '<div class="task %s">%s%s</div>',
            ($elm->getName() == '__template__') ? 'template' : '',
            $inputDesc,
            $inputCompleted
        );
 
        // this should be the first decorator but add the content for
        // consistency's sake
        return $content . $elmHtml;
    }

My_Validator_TaskElement

A custom validator is added: My_Validator_TaskElement (see code on GitHub). This validator will check if the description is empty but treats new elements differently from existing ones: For existing elements it is not allowed to have an empty description. For new elements this is only allowed if the ‘completed’ checkbox isn’t checked. (This way a user can still submit the form if he’d accidentally added a new field).

Using jQuery to let the user add new elements

The javascript that lets a user add a new element is implemented as a jQuery plugin. The code having the javascript initiate looks as follows:

$(document).ready(function() {
    $('form .taskDay').dynamicForm();
});

As can be seen each of the ‘day’ subforms outer elements is selected and applied upon a jQuery plugin. This plugin (on GitHub)performs the following tasks:

  • Within the element it operates on it searches for an element with classname ‘add’ and attaches a ‘click’ event handler to it.
  • It searches for an element ‘template’ and stores a reference to it.
  • Whenever the user clicks the ‘add’ button, the template element is cloned
  • Within the template element the ‘name’ attribute of any input element is altered: The string ‘__template__’ is replaced by a timestamp. This makes sure that multiple new tasks can be added within a day without them interfering with each other.
  • The new element is placed after the last found element with classname ‘task’

By referring to classnames, the javascript’s dependencies on the exact HTML are kept to a minimum. This way, if needed, the HTML structure of the form elements can be changed without the need to update the javascript.

Having the form process the new elements

When the task form is submitted, newly added tasks will be in the $_POST array as shown below:

// is assoc. array having 'desc' and 'completed' keys
$_POST[$dayTimestamp]['new'][$uniqueJSCreatedValue];

The form object needs to be able to validate the input for both the existing and the new tasks, so the $_POST array is passed to the isValid() method. At this point the form doesn’t yet contain the ‘new’ elements. Adding those is done in a similar fashion to how the existing elements are added in setDefaults(), only this time it is done in isValid(). That is the first point where the form is able to determine what the new elements are. Dynamically adding the new elements happens in the ‘day’ subform:

class My_SubForm_TaskDay extends Zend_Form_SubForm
{
    // ...
    public function isValid($data) {
        $subform = $this->getSubForm('new');
        // make sure new is array (won't be in $data if nothing submitted)
        if (!isset($data['new'])) {
            $data['new'] = array();
        }
        foreach ($data['new'] as $idx => $values) {
            // Don't add element with idx = __template__. SetIgnore works on
            // getValues. Template elements are submitted so this would otherwise
            // override the previously added template element, thereby losing the
            // setIgnore setting...
            if ($idx !== '__template__') {
                $subform->addElement($this->createTaskElement($idx, $data, true));
            }
        }
        // call parent, which will populate newly created elements.
        return parent::isValid($data);
    }
    //...
}

Here the aforementioned createTaskElement() method pops up again. Notice the third parameter (true) that will make the validator treat the element as a ‘new’ one.

All done, except for …

In theory now everything works. But practice tends to have those little things that go wrong which you hardly ever read about in code examples. When working on this example I noticed that getValues() doesn’t preserve the per-day timestamp keys in the array returned. Instead, it returns an indexed array like this:

$getValues = array(
    // this '0' should have been a timestamp, like: 1261350000
    '0' => array(
        'current' => array(), // etc. etc.
        'new' => array() // etc. etc.
    ),
    // ...
);

Bummer. As it appears, Zend_Form ‘requires’ elements, subforms and display groups to have valid variable names (See ZF-4204). One of the reasons is problably that the names also end up in HTML id attributes which are not allowed to start with a number. The name attribute is though (you can run the demo form through the W3C validator). Remarkably, the task elements, having a name consisting of the database id, are processed just fine.

Two possible solutions for this:

  • Avoid numeric names. Downside is that this also involves changing the existing code generating and processing the array. The day-form header decorator which uses the form’s name to display the date needs to be changed as well.
  • Add an implementation of getValues() in My_Form_TaskWeek that checks for numeric keys and changes them back to their original timestamp

I choose the latter (for now) because it allows to leave almost all existing code unaltered and the resulting behaviour is unit testable (supply defaults, test what is rendered, test what is returned, etc.).

Conclusion

The above shows that:

  • Subforms are very useful to repeat similar blocks within a form and to group related values in the returned value array.
  • Dynamically adding initial and newly submitted elements follows a similar pattern: Add elements based on the passed in array and then call the parent’s method. This is done in setDefaults() and isValid() respectively.

The question might arise ‘is Zend_Form the best solution for this type of customized form?’. The default ViewHelper decorator is ignored, no default validator is used. I can’t tell if Zend_Form is the best solution but fact is that it provides a lot of functionallity and flexibility: The Form, Errors and HtmlTag decorators are used ‘as is’. Furthermore, the option to reuse parts comes almost naturally because of Zend_Form’s design.

Regarding the last point I’ll conclude with following example: What if, some time after having created this form, the idea is born to have some sort of per-day dashboard page where a user can view and edit things like calendar, messages and tasks? (This is the kind of stuff that happens in agile projects). Reusing My_SubForm_TaskDay would be very useful. And luckily that is easily accomplished. All that is needed is wrapping the subform in a class that will additionally:

  • Set a view object
  • Add a submit button
  • Add a Form decorator

See the code of My_Form_TaskDay on GitHub or see it in action online.

  • Twitter
  • LinkedIn
  • Facebook
  • StumbleUpon
  • DZone

Using Zend_Form without Zend Framework MVC

Tibo BeijenDecember 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:

  • Twitter
  • LinkedIn
  • Facebook
  • StumbleUpon
  • DZone

Fronteers 2009

Tibo BeijenNovember 7th, 2009
fronteers-2009

About five months after having enjoyed server-side talks at DPC09 it was now time for front-end matters: Fronteers 2009. There’s no exaggeration in the description on the fronteers site: A stellar line up of speakers who are at the front of what’s happening in web-development. Generally speaking I really liked most of the talks and some of them pointed me to some interesting new techniques and ideas.

Slides of the presentation (if online) are listed at the Fronteers site and at the end of this post (same content, read along). I’ll briefly recap some of the (for me that is) most interesting parts.
more…

  • Twitter
  • LinkedIn
  • Facebook
  • StumbleUpon
  • DZone

Catching PHP Exceptions: Except the unexpected

Tibo BeijenOctober 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…

  • Twitter
  • LinkedIn
  • Facebook
  • StumbleUpon
  • DZone

Usability: What does this button do?

Tibo BeijenOctober 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…

  • Twitter
  • LinkedIn
  • Facebook
  • StumbleUpon
  • DZone