Custom View Helpers in Zend Framework

June 26, 2006

by — Posted in Zend Framework

The Zend Framework Manual describes View Helpers like so:

“In your view scripts, often it is necessary to perform certain complex functions over and over; e.g., formatting a date, generating form elements, or displaying action links. You can use helper classes to perform these behaviors for you.”

Currently the framework (version 0.1.3) includes a small selection of form helpers which will no doubt expand as it matures. For now I’m more interested in the ability to add custom helpers for specific project use. The first thing I did was to set up the same directory structure as Zend_View_Helper as is suggested when subclassing controllers:

library/
    Zend/
        View/
            Helper/
    MyProject/
        View/
            Helper/

Having my project specific helper files in library/MyProject/View/Helper/ will make it easy to keep them separate from Zend core updates.

The next step is to tell Zend_View to look in the custom helper directory as well as the default Zend helper directory. This just requires adding the new helper path to the Zend_View object I created in the public_html/index.php file:

$view = new Zend_View;
$view->addHelperPath('MyProject/View/Helper');

Cautionary Note (* see update below)

The above is actually a bit of a fiddle to get working if you decide like I did to use a relative path to your helper files. I had set…

set_include_path( /home/exciting_zfw_site/library/ );

…pointing to the main Zend library directory, however, Zend_View_Abstract:: _loadClass() uses is_readable() as a check before loading any helper or filter files like so…

if (is_readable($dir . $file)) {
    include $dir . $file;

    if (! class_exists($class, false)) {
        $msg = "$type '$name' loaded 
                        but class '$class' not found within";
        throw new Zend_View_Exception($msg);
    }

    return $class;
}

…and since is_readable just ignores include paths, your new helper files won’t be found. This is currently listed as a bug but for the moment I simply changed…

if (is_readable($dir . $file)) {
    include $dir . $file;

…to…

if (include $dir . $file) {

…and it worked fine. Portability was the reason I wanted to keep the paths relative as I move files from a development server to the live server. It’s much easier to keep as few path configuration settings as possible.

The next step is pretty well documented in the manual but for the sake of completeness I’ll keep going. Create a new helper file:

class Zend_View_Helper_DoStuff {

    public function doStuff()
    {
        return 'Hello to you all';
    }
}

Another Cautionary Note

Something that caught me out was that the new helper class must be called Zend_View_Helper_YourNameHere rather than MyProject_View_Helper_YourNameHere which seems a little odd considering it’s position in the directory structure I mentioned before. While logically it is a Zend_View helper class, it will be kept with other subclassed files with your own “namespaced” class names under the MyProject directory so it seems to break a convention.

Ready to use

After saving the new helper file in MyProject/View/Helper/DoStuff.php it should be available to use in your view scripts like so:

<?php echo $this->doStuff(); ?>

When writing helper classes the key points to initially getting them to work are the naming conventions as illustrated by my doStuff example:

  1. Class name must be Zend_View_Helper_DoStuff
  2. The class must contain a public function doStuff()
  3. The file must be save as DoStuff.php

As mentioned in my post on getting to know Zend_View elements of the above may well change as development continues.

Further Reading

View Helpers in the Zend Framework Manual

* Update

Forget the above hack…

if (include $dir . $file) {

…as it will produce warnings as Zend_View_Abstract::_LoadClass() attempts to include the doStuff file from any other path in the _path stack. Instead the only solution I’ve found to currently work is to specify a relative path like so:

$view->addHelperPath('../MyProject/UW/View/Helper');