Friday, November 9, 2012

Zend Framework 1 - Zend Form Custom Error Handling

Greetings Programs!
Zend Forms... a black art?

At first it may seem but spend some time and you just might realize how powerful they are. Over the past two years I have been working with the Zend framework and have become very fond of it. It is not overly prescriptive and allows me to exercise pattern design extending it and bending it to my will. I will admit that early on zend form decorators was a major challenge. It wasn't until design and front end requirements really pushed me to see how far I could extend zend forms. After a number of big challenges I realized there's a lot you can do with zend forms and decorators.

In this blog we are going to look at a Zend form and how we control error display. In a nutshell we want to....
1: Show only a "*" next to fields that have errors. 
2: Show only one error in an error field <div> based on priority.
3: decorate the form in a <div> structure.

The real problem we are trying to solve is the potential endless diarrhea of errors that can spill out of the form onto our UI and just mess everything up. 
Code can be found here: https://github.com/jdellostritto/ZTMPL_formerrors.git

So here is what we want to see in this very simple registration form.


You will notice that the email format is incorrect above. The error message tells the user and is our first priority message. Note: the password fields are incorrect (empty) as well and the form indicates that however, we don't spill those errors messages out all over the screen.

Here is a submission with a correct email format:

Notice that the email is correct and we only see the required field error because I failed to put in either the password or the confirm password. Next I will enter a password in the password field that is too short so I expect to see a length failure.


As you can see we are walking through the process one input at time. We are not leaving the user with out cues for the fields that are invalid however, we are controlling the mess that could ensue especially if we have a form with a lot of fields and many errors.  This allows us to keep our UI 'Crispy' (ref: Crispy is term used by a front end designer I know his name is Kalim).

WHAT DECORATORS DO WE NEED TO PULL THIS OFF.

Below is the HTML structure we want to use to make this work. You should always start with a definition of you ideal structure. Don't be afraid of how complex it might look. I haven't encountered a structure I couldn't resolve with decorators and zend forms.
<form>
   
   <div class="input">
   <input type="text" name="emailaddress" id="emailaddress" value="" placewholder="email address">
   <div id="error_condition_input">zend element <ul> error</div>
   </div>

   <div class="input">
   <input type="password" name="password" id="password" value="" placeholder="choose a password">
   <div id="error_condition_input">zend element <ul> error</div>
   </div>

   <div class="input">


   <input type="password" name="confirmpassword" id="confirmpassword" value=""  placeholder="confirm password">
   <div id="error_condition_input">zend element <ul> error</div>
   </div>

   <div class="submit">
   <input type="image" name="submit_reg" id="submit"    src="/zendformsample1/public/media/img/forms/next.png" type="image">
   </div>

</form>
<div id="error_condition_form">zend form <ul> custom error</div>   

First: Notice that each input has it's own <div id="error_condition_input"><div>. This is were the "*" asterisk will show up when the input is invalidated. 

Second: notice the <div id="error_condition_form"></div> at the end after the form. This is were we will show the custom error based on a priority that we set.

DECORATING THE TOP LEVEL FORM. 
I choose to decorate the form in stages. I start simply start by calling a function in my form class to do just that (function can be found in Application_Form_Index_Register Class on github).The setDecorators function is called on the form to create our default structure. Notice that we wrap our errors in the div based on the HTML structure we defined earlier. ...
DECORATING THE INPUT BOX
In the code below we define a function that will allow us to decorate our input boxes. The code above should look familiar. Wrapping the error generated by the input is accomplished the same way it was accomplished at the form level. We then wrap the whole thing in a <div> in the last line. ...

DECORATING THE SUBMIT BUTTON IMAGE
We only have a single submit button so we decorate it when we create it. If we have more than one it would make sense to move this function out into a separate function.In the _render_submit()function setDecorators is called on the submit button wrapping it in a <div> with a class = "submit".

...


TEST FOR ERRORS
At this point we should be all 'decorated up'. Each input has a nice div element for errors as does our form. With a little CSS we can move things around and have a nice looking form (see sample CSS on github). Below you will find the code for processing and setting the errors.  ...
The code above grabs the form errors which contains a listing of all the errors from each input in the order the input presents itself on the page. Using this ordering we prioritize the capture of the error and use the setErrors function for the form which overwrites any previously set error messages and flags a failed validation. It will then return. Remember the individual input errors are preserved and each is set to display "*". For more information on how this is done you'll need to look at the class Application_Form_Index_Register and the validators that are used for each input box. Again these are available on github. 

I have some other small tricks in this baseline on github that I have learned from many sources... too many to list (css helpers, resource loading, etc.). I am also aware that there are alternate approaches and some may be more clever than mine. I am happy to learn so please comment and suggest.

...You've enjoyed all the power you've been given, haven't you. I wonder how you'd take to working in a pocket calculator...
...
End of line

Master Control Program: Tron 1982




No comments:

Post a Comment