During form rendering, the decorators are executed in the order added and rendering are done on the same content throughout. If you were to open up Zend/Form.php, you will find inside an elegant render method as follows that summarizes what I’ve mentioned earlier.

public function render(Zend_View_Interface $view = null)
{
    if (null !== $view) {
        $this->setView($view);
    }

    $content = '';
    foreach ($this->getDecorators() as $decorator) {
        $decorator->setElement($this);
        $content = $decorator->render($content);
    }
    return $content;
}

Here comes the issue. We cannot apply decorators selectively to a part of the content by breaking it up. You can only prepend, append or wrap the whole, not portion of, content with a new decorator. This poses a challenge if you need to create custom tags around both Label and Text Field in a Zend_Form_Element_Text for example.

If you, like me, have been doing lots of research on Zend Form Decorators and is hitting the wall, I guess the following might be a solution that will give flexibility to the way decorators can be used. I hope this will help someone in a way or another.

Before I start presenting the possible solution, let me go through what we want to achieve, what we can achieve using the closest available method on the Internet and my proposed solution that introduces flexibility to what we want to achieve.

What we want to achieve

As an example, here’s what we want to achieve, a class attribute of value label for the first td tag on line 2. This will allow us to style it with CSS class label.

<tr>
    <td class="label">
        <label for="username" class="optional">Username:</label>
    </td>
    <td class="element">
        <input type="text" name="username" id="username" value="" />
    </td>
</tr>

What we can achieve using the closest available method

Here are the decorators applied to Zend_Form_Element_Text instance. On line 5, we have added an option ‘class’ => ‘label’ to the Label decorator.

$element->setDecorators(array(
    'ViewHelper',
    'Errors',
    array(array('data' => 'HtmlTag'), array('tag' => 'td', 'class' => 'element')),
    array('Label', array('tag' => 'td', 'class' => 'label')),
    array(array('row' => 'HtmlTag'), array('tag' => 'tr')),
));

The following is achieved using the above code. As you can see, class label is applied to label tag on line 3, and not td tag on line 2. This is not what we want.

<tr>
    <td>
        <label for="username" class="label optional">Username:</label>
    </td>
    <td class="element">
        <input type="text" name="username" id="username" value="" />
    </td>
</tr>

Proposed solution

We will create two new decorator class: Store and Retrieve. It will be used as follows.

$username->setDecorators(array(
    // Create element and store it.
    'ViewHelper',
    'Errors',
    array(array('td-element' => 'HtmlTag'), array('tag' => 'td', 'class' => 'element')),
    array(array('store-element' => 'Store'), array('clear' => true)),

    // Create label and store it.
    'Label',
    array(array('td-label' => 'HtmlTag'), array('tag' => 'td', 'class' => 'label')),
    array(array('store-label' => 'Store'), array('clear' => true)),

    // Retrieve both the label and element.
    array(array('retrieve-label' => 'Retrieve'), array('name' => 'store-label', 'remove' => true)),
    array(array('retrieve-element' => 'Retrieve'), array('name' => 'store-element', 'remove' => true)),

    // Wrap the retrieved label and element with tr tag.
    array(array('row' => 'HtmlTag'), array('tag' => 'tr')),
));

The following is achieved using the above code as what we have set out initially. We are now able to work on part of the content at a time.

<tr>
    <td class="label">
        <label for="username" class="optional">Username:</label>
    </td>
    <td class="element">
        <input type="text" name="username" id="username" value="" />
    </td>
</tr>

In Part 2, we will present the two newly derived decorator class.

Excellent References:
http://framework.zend.com/manual/en/zend.form.standardDecorators.html
http://devzone.zend.com/article/3450-Decorators-with-Zend_Form
http://zendguru.wordpress.com/2008/10/23/zend-form-decorators/