Well, after playing with Zend_Form for the past few days, I came across a lack of elements for the form I was working on. First, let’s look at the form I was working on. This is just a simple login form:
<div id="wrap">
<div id="inner">
<form action="" method="post">
<fieldset>
<h1><a href="#back" title="Return to: MyApp.com">Return to MyApp.com</a></h1>
<h2>Login to MyApp</h2>
<p id="username"><input type="text" value="Please enter your username here..." onblur="if(this.value=='') this.value='Please enter your username here...';" onfocus="if(this.value=='Please enter your username here...') this.value='';" /></p>
<p id="password"><input type="password" value="********" onblur="if(this.value=='') this.value='********';" onfocus="if(this.value=='********') this.value='';" /></p>
<p id="forgot"><a href="#forgot">Forgotten your password? Click here.</a></p>
<p id="loginBtn"><input type="submit" value="Login here" /></p>
</fieldset>
</form>
</div>
</div>
As you can see, I have two elements here that will not work with the stock implementation of Zend_Form. For those of you that have never worked with Zend_Form_Elements, you will find that each element has two classes. The first thing you have is the actual element; after that, you have the view helper. Typically, the element class is simple and in most cases consists of just one variable, with the rest obtained from the abstract element class. Let’s take a look at my first added element: MyApp_Form_Element_Heading
class MyApp_Form_Element_Heading extends Zend_Form_Element_Xhtml
{
/**
* Default form view helper to use for rendering
* @var string
*/
public $helper = 'formHeading';
/**
* Set H level
*
* @var int $level
* @return MyApp_Form_Element_Heading
*/
public function setLevel($level)
{
$this->level = $level;
return $this;
}
}
I did add in one method to this class to set the heading “level”(1-6). This is just to make the actual code a little prettier. Everything here is fairly simple, so let’s move on to the view helper: MyApp_View_Helper_FormHeading
class MyApp_View_Helper_FormHeading extends Zend_View_Helper_FormElement
{
public function formHeading($name, $value, $attribs = null)
{
$info = $this->_getInfo($name, $value, $attribs);
extract($info); // name, value, attribs, options, listsep, disable
$level = $attribs['level'];
unset($attribs['level']);
$level = 'h' . $this->view->escape($level);
$xHtml = '< ' . $level
. ' id="' . $this->view->escape($id) . '"'
. $this->_htmlAttribs($attribs)
. '>'
. $value
. "< /$level>"
return $xHtml;
}
}
Again, this is all straightforward if you’re familiar with PHP. The only thing that is a little fuzzy, if you’re not, is the extract() function. Essentially all this does is “extract” the array keys as actual variables. For more of how this works just check out the PHP Manual. Past this, we pull the level variable from the attributes and unset it so it doesn’t add it as its own attribute to the heading tag. Then, simply set the return value in such a way that it is xHtml valid. You will notice that I didn’t escape the $value variable. This is because in the form I am working on the heading is a link. I’m sure there are easier and cleaner ways of going about this, but I’ll worry about that later
. Now the next element: MyApp_Form_Element_Link
class MyApp_Form_Element_Link extends Zend_Form_Element_Xhtml
{
/**
* Default form view helper to use for rendering
* @var string
*/
public $helper = 'formLink';
/**
* Set href
*
* @var string $href
* @return MyApp_Form_Element_Link
*/
public function setHref($href)
{
$this->href = $href;
return $this;
}
}
Once again, you’ll notice this is extremely simple. Only added in a setHref() method to finish, again just for aesthetics. Everything else is exactly the same as above. Moving on: MyApp_View_Helper_FormLink
class MyApp_View_Helper_FormLink extends Zend_View_Helper_FormElement
{
public function formLink($name, $value, $attribs = null)
{
$info = $this->_getInfo($name, $value, $attribs);
extract($info); // name, value, attribs, options, listsep, disable
$xHtml = '<a '
. $this->_htmlAttribs($attribs)
. '>'
. $value
. '</a>';
return $xHtml;
}
}
Again, this is all exactly as above. Using these two elements, I was able to build all of the form, save for one element. Notice that in the original form I was working on, that it has a pre-populated password value. Using the basic Zend_View_Helper_FormPassword you cannot do this. It will not populate the value even if you set it. I got around this with the following extension of that class: MyApp_View_Helper_FormPassword
class MyApp_View_Helper_FormPassword extends Zend_View_Helper_FormElement
{
/**
* Generates a 'password' element.
*
* @access public
*
* @param string|array $name If a string, the element name. If an
* array, all other parameters are ignored, and the array elements
* are extracted in place of added parameters.
*
* @param mixed $value The element value.
*
* @param array $attribs Attributes for the element tag.
*
* @return string The element XHTML.
*/
public function formPassword($name, $value = null, $attribs = null)
{
$info = $this->_getInfo($name, $value, $attribs);
extract($info); // name, value, attribs, options, listsep, disable
// is it disabled?
$disabled = '';
if ($disable) {
// disabled
$disabled = ' disabled="disabled"';
}
// determine the XHTML value
$valueString = ' value="'.$value.'"';
if (array_key_exists('renderPassword', $attribs)) {
if ($attribs['renderPassword']) {
$valueString = ' value="' . $this->view->escape($value) . '"';
}
unset($attribs['renderPassword']);
}
// XHTML or HTML end tag?
$endTag = ' />';
if (($this->view instanceof Zend_View_Abstract) && !$this->view->doctype()->isXhtml()) {
$endTag= '>';
}
// render the element
$xhtml = '<input type="password"'
. ' name="' . $this-/>view->escape($name) . '"'
. ' id="' . $this->view->escape($id) . '"'
. $valueString
. $disabled
. $this->_htmlAttribs($attribs)
. $endTag;
return $xhtml;
}
}
The only thing that I changed in this class is the value line. I changed it from
$valueString = ' value=""';
to
$valueString = ' value="'.$value.'"';
to allow for the population of the value for the class.
Well, that’s the end of this long blog post. I have to say that no matter how much headache this has caused me, the Zend_Form class is extremely clean and powerful. The validation and filtering tools make checking forms extremely easy. Add to this the fact that even when you don’t have the element you’re looking for in the stock implementation, its not that hard to add it, Zend_Form is a powerful tool for any developer to have in their bag of tricks.