Recently I've had the humbling experience of formatting Zend Forms using their "Decorator" Pattern. The reason we use the Zend_Form class is its concrete validation and filtering for form fields, not because they're nice to style. Once you understand how to apply quick and simple custom decorators instead of writing classes that extend Zend's Decorator class it's not so bad.
You could have a quick look at the Zend Documentation for decorators (Don't actually do it, their documentation isn't great for this, it describes the process of writing complete custom Decorator classes that extend their Zend_Form_Decorator_Abstract, this is timely and unnecessary for most cases), or preferably read this article called "Decorators with Zend_Form" that explains them really well. If the second article isn't quite practical enough, or you are still confused with Zend Form Decorators then I'm going to give you a few hints on how to better make use them of.
Standard Zend Form Decorator
Zend Form Decorator Example
class My_Form extends Zend_Form {
protected $_formDeco = array(
'FormElements',
array('HtmlTag', array('tag' => 'div', 'class' => 'grid_6')),
'Form'
);
...
$this->setDecorators($this->_formDeco);
This is what we're going to use to define how our form is rendered in HTML. If you read "Decorators with Zend_Form" you will know where this is going... This array named $_formDeco is actually a list of 3 standard Zend Form Decorators. First the 'Form' decorator prints the 'Form' tag and adds any necessary attributes to your form tag such as when you're using a File input field.
Next is the standard Zend 'HtmlTag' Decorator, what this is going to do is render a <div> tag around our form fields instead of the standard <dl> tag that Zend Forms use naturally. I'm also specifying a attribute=>value pair in the options for the css class so it will add class="grid_6" to the element.
If you havn't noticed, the decorators at the end of the array are the parent of the previous decorators. So Form will be the parent of the div tag, and the div tag will be the parent of the FormElements. There are some decorators that do not follow this pattern, these include snippets of HtmlCode that are instead appended or prepended to certain elements.
The 'FormElements' decorator just iterates over every element and renders them.
What decorators am I dealing with on this element?
Print element decorators
$yourElement = new Zend_Form_Element_Radio('elementId');
print_r($yourElement->getDecorators());
will print out the decorators used by an element. For example using this on a Zend_Form_Element_Radio tells us they have 5 standard decorators.
Zend Radio Element Decorator Example
protected $_standardRadioDeco = array(
'ViewHelper',
'Errors',
'Description'
array('HtmlTag', array('tag'=>'dd'))
array('Label', array('tag'=>'dt'))
);
There are also a few other options, but that is the jist of it. The ViewHelper decorator is actually what is printing the <input .../> element, and the rest should make sense. If you want to customise your radio elements to not use the dd and dl tags, you would set custom decorators on your elements.
Custom Zend Radio Decorator Example
Here is an example of an array of decorators I have applied to some of my own radio elements in place of the regular definiton list layout Zend Uses.
Custom Radio Element Decorator Example
protected $_standardRadioDeco = array(
'ViewHelper',
array('HtmlTag', array('tag' => 'div', 'class'=>'form-radio-div')),
'Errors',
array('Description', array('tag' => 'p', 'class' => 'description')),
array('Label', array('tag' => 'div'))
);
protected $_radioDecoSeparator = '</div><div class="form-radio-div">';
...
$radioElement->setDecorators($this->_standardRadioDeco)
->setSeparator($this->_radioDecoSeparator);
With this ordering of Standard Decorators we can expect...
- The Standard ViewHelper Decorator will render the input tag and add any attributes like id, class, etc.
- The Standard HtmlTag Decorator will render <div> tags with the form-radio-div class around the ViewHelper Decorator.
- The Standard Errors Decorator renders a <ul> by itself after the Element.
- The Description and Label Decorators are rendered similarly to the Errors Decorator, they do not wrap the previous Decorators and are placed before the elements, we've also used the 'tag' option to specify this decorator should render <div> and <p> tags around each element.
- The Zend_Form_Element_Radio Decorator naturally uses a seperator between each <input> tag, and we use this here to contain each radio input element to a <div> box for formatting puposes.
I will continue this article later with more examples of Zend Decorators and a whole form example. Please show your interest in the comments if this helped!
Adam Jacquier-Parr is a Junior Software Engineer at Crowdcomms who designs, develops and maintains web applications for conferences and events.