Quick and dirty custom Zend_Form_Decorator_Label

Someone on the zf-mvc list asked the following question:

how to add elements like the description between label and input, for example:

<dt>
    <label>Your E-Mail: *</label><span class="Description">- won't be published</span>
</dt>
<dd>
    <input value="" id="email" class="" type="text" />
</dd>

This is currently not possible out of the box with Zend_Form. I put on my problem-solving-hat and quickly made a rather dirty implementation of a custom decorator to solve the problem specified above. I made a class called My_Form_Decorator_LabelWithDescription that extends the Zend_Form_Decorator_Label class. My custom label class looks like this:

<?php
require_once 'Zend/Form/Decorator/Label.php';

class My_Form_Decorator_LabelWithDescription extends Zend_Form_Decorator_Label {
    /**
     * Description decorator
     *
     * @var Zend_Form_Decorator_Description
     */
    protected $_description = null;

    /**
     * Set the description decorator
     *
     * @param Zend_Form_Decorator_Description $description
     * @return My_Form_Decorator_LabelWithDescription
     */
    public function setDescription(Zend_Form_Decorator_Description $description) {
        $this->_description = $description;
        return $this;
    }

    /**
     * Get the description decorator
     *
     * @return Zend_Form_Decorator_Description
     */
    public function getDescription() {
        return $this->_description;
    }

    public function render($content) {
        $element = $this->getElement();
        $view    = $element->getView();
        if (null === $view) {
            return $content;
        }

        $label     = $this->getLabel();
        $separator = $this->getSeparator();
        $placement = $this->getPlacement();
        $tag       = $this->getTag();
        $id        = $this->getId();
        $class     = $this->getClass();
        $options   = $this->getOptions();

        if (empty($label) &amp;&amp; empty($tag)) {
            return $content;
        }

        if (!empty($label)) {
            $options['class'] = $class;
            $label = $view->formLabel($element->getName(), trim($label), $options);
        }

        if (null !== $this->_description) {
            $this->_description->setElement($element);
            $label = $this->_description->render($label);
        }

        if (null !== $tag) {
            require_once 'Zend/Form/Decorator/HtmlTag.php';
            $decorator = new Zend_Form_Decorator_HtmlTag();
            $decorator->setOptions(array('tag' => $tag));
            $label = $decorator->render($label);
        }

        switch ($placement) {
            case self::APPEND:
                return $content . $separator . $label;
            case self::PREPEND:
                return $label . $separator . $content;
        }
    }
}

I have added a protected $_description property and a set/get method for it.

The render method is simply copied from the parent class with a small modification:

if (null !== $this->_description) {
    $this->_description->setElement($element);
    $label = $this->_description->render($label);
}

This will render the description and add it to the label.

The last part of this post will show you how to enable this marvelous new decorator. I will use some code from my Translating Zend_Form error messages and more post, so if you haven’t read that yet you should catch up by doing so. :)

In the mentioned post I had some custom elements that added decorators. Lets add this new decorator to the custom text fields. The My_Form_Element_Text class looked like this:

<?php
require_once 'Zend/Form/Element/Text.php';

class My_Form_Element_Text extends Zend_Form_Element_Text {
    public function init() {
        $this->setDecorators(array(
             array('ViewHelper'),
             array('Description', array('escape' => false,
                                        'class' => 'fieldDescription')),
             array('Errors'),
             array('HtmlTag', array('tag' => 'dd')),
             array('Label', array('requiredSuffix' => ' *',
                                  'tag' => 'dt',
                                  'escape' => false))
        ));
    }
}

As you can see both the Label and Description decorators are added, but since my decorator includes the Description within the Label we don’t need both! After a little modification, the class now looks like:

<?php
require_once 'Zend/Form/Element/Text.php';
require_once 'Zend/Form/Decorator/Description.php';
require_once 'My/Form/Decorator/LabelWithDescription.php';

class My_Form_Element_Text extends Zend_Form_Element_Text {
    public function init() {
        $description = new Zend_Form_Decorator_Description(array(
            'tag' => 'span',
            'escape' => false,
            'class' => 'fieldDescription'));

        $label = new My_Form_Decorator_LabelWithDescription(array(
            'requiredSuffix' => ' *',
            'tag' => 'dt',
            'escape' => false));

        // Add the description decorator to the label
        $label->setDescription($description);

        $this->setDecorators(array(
             array('ViewHelper'),
             array('Errors'),
             array('HtmlTag', array('tag' => 'dd')),
             array($label)
        ));
    }
}

And voila! You now have a fully customizable Description decorator that will be rendered inside the Label. Pretty neat eh?

This is not exactly the best implementation of such a decorator but it gets the job done. It would be cool if some hooks where added to the default decorator that child classes could implement. That way I wouldn’t have to copy the entire render method from the Label decorator.

Advertisements
This entry was posted in PHP, Technology and tagged , , , . Bookmark the permalink.

5 Responses to Quick and dirty custom Zend_Form_Decorator_Label

  1. :)
    Thanks for your work man, that’s exactly what i’m searching for.

    Dennis

  2. Pingback: Mats Lindh

  3. Pingback: Christer Puts on His Problem Solver Hat | Mats Lindh

  4. Pingback: 2008 is almost at an end « Christer’s blog o’ fun

  5. Diego says:

    Awesome ! Perfect !!!!, It is what I was looking for.

    Many thanks,
    Diego

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s