Zend Framework Zend_Form Decorators: <span> Inside Button Element?

leek picture leek · Apr 22, 2009 · Viewed 15k times · Source

I have a button element that I've created like so:

$submit = new Zend_Form_Element_Button('submit');
$submit->setLabel('My Button');
$submit->setDecorators(array(
    'ViewHelper',
     array('HtmlTag', array('tag' => 'li'))
));
$submit->setAttrib('type', 'submit');

This generates the following HTML:

<li>
    <label for="submit" class="optional">My Button</label> 
    <button name="submit" id="submit" type="submit">My Button</button>
</li>

I would like to wrap the inside of the button with a <span>, like this:

<button...><span>My Button</span></button>

What is the best way to do this using Zend_Form?

Answer

Kieran Hall picture Kieran Hall · May 1, 2009

I have tried and, ultimately, failed to achieve this myself using the same approach. It would seem that the easiest way to do this would be to do:

...
$submit->setLabel('<span>My Button</span>');
...

However, the span will be escaped. It's perfectly possible to turn off the escaping of a lable decorator, however, adding a label decorator renders the output incorrectly, for instance:

$decorator = array(
    array('ViewHelper'),
    array('HtmlTag', array('tag' => 'li')),
    array('Label', array('escape' => false))
);

$submit = new Zend_Form_Element_Button('submit');
$submit->setLabel('<span>My Button</span>');
$submit->setDecorators($decorator);
$submit->setAttrib('type', 'submit');

... renders:

<label for="submit" class="optional"><span>My Button</span></label>
<li>
    <button name="submit" id="submit" type="submit">&lt;span&gt;My Button&lt;/span&gt</button>
</li>

...which, aside from being semantically incorrect (easily fixable), is still escaping the span tags inside the element.

So what do you do?

Well I think the best approach (and this is my meta-advice when it comes to tight control over Zend_Form rendering) is to use the ViewScript decorator.

$submit = new Zend_Form_Element_Button('submit');
$submit->setLabel('My Button');
$submit->setDecorators(array(array('ViewScript', array('viewScript' => '_submitButton.phtml'))));
$submit->setAttrib('type', 'submit');

...then in _submitButton.phtml define the following:

<li>
    <?= $this->formLabel($this->element->getName(), $this->element->getLabel()); ?>
    <button 
    <?php 

    $attribs = $this->element->getAttribs();

    echo
    ' name="' . $this->escape($this->element->getName()) . '"' .
    ' id="' . $this->escape($this->element->getId()) . '"' . 
    ' type="' . $this->escape($attribs['type']) . '"';
    ?>
    <?php

    $value = $this->element->getValue();

    if(!empty($value))
    {
        echo ' value="' . $this->escape($this->element->getValue()) . '"';
    }
    ?>
    >
    <span>
    <?= $this->escape($this->element->getLabel()); ?>
    </span>
    </button>
</li>

The _submitButton.phtml file will need to be in a view script directory (you might be best adding a specific one for your form decorators using $view->addScriptPath('/path/to/my/form/decorators')).

This should render what you're looking for. I've only just started looking at the ViewScript decorator due to flexibility issues I'm experiencing in work. You'll notice that my script isn't that flexible, and certainly isn't in BNF, given all the members that can be populated on the element object. That said, it's a start and it solves your problem.