Creating Form Elements Using Zend_Form_ElementA form is made of elements that typically correspond to HTML form input. Zend_Form_Element encapsulates single form elements, with the following areas of responsibility:
The base class, Zend_Form_Element, has reasonable defaults for many cases, but it is best to extend the class for commonly used special purpose elements. Additionally, Zend Framework ships with a number of standard XHTML elements; you can read about them in the Standard Elements chapter. Plugin LoadersZend_Form_Element makes use of Zend_Loader_PluginLoader to allow developers to specify locations of alternate validators, filters, and decorators. Each has its own plugin loader associated with it, and general accessors are used to retrieve and modify each. The following loader types are used with the various plugin loader methods: 'validate', 'filter', and 'decorator'. The type names are case insensitive. The methods used to interact with plugin loaders are as follows:
Custom validators, filters, and decorators are an easy way to share functionality between forms and to encapsulate custom functionality. Example #1 Custom Label One common use case for plugins is to provide replacements for standard classes. For instance, if you want to provide a different implementation of the 'Label' decorator -- for instance, to always append a colon -- you could create your own 'Label' decorator with your own class prefix, and then add it to your prefix path. Let's start with a custom Label decorator. We'll give it the class prefix "My_Decorator", and the class itself will be in the file "My/Decorator/Label.php".
Now we can tell the element to use this plugin path when looking for decorators:
Alternately, we can do that at the form level to ensure all decorators use this path:
After it added as in the example above, the 'My/Decorator/' path will be searched first to see if the decorator exists there when you add a decorator. As a result, 'My_Decorator_Label' will now be used when the 'Label' decorator is requested. FiltersIt's often useful and/or necessary to perform some normalization on input prior to validation. For example, you may want to strip out all HTML, but run your validations on what remains to ensure the submission is valid. Or you may want to trim empty space surrounding input so that a StringLength validator will use the correct length of the input without counting leading or trailing whitespace characters. These operations may be performed using Zend_Filter. Zend_Form_Element has support for filter chains, allowing you to specify multiple, sequential filters. Filtering happens both during validation and when you retrieve the element value via getValue():
Filters may be added to the chain in two ways:
Let's see some examples:
Short names are typically the filter name minus the prefix. In the default case, this will mean minus the 'Zend_Filter_' prefix. The first letter can be upper-cased or lower-cased.
If at any time you need the unfiltered value, use the getUnfilteredValue() method:
For more information on filters, see the Zend_Filter documentation. Methods associated with filters include:
ValidatorsIf you subscribe to the security mantra of "filter input, escape output," you'll should use validator to filter input submitted with your form. In Zend_Form, each element includes its own validator chain, consisting of Zend_Validate_* validators. Validators may be added to the chain in two ways:
Let's see some examples:
Short names are typically the validator name minus the prefix. In the default case, this will mean minus the 'Zend_Validate_' prefix. As is the case with filters, the first letter can be upper-cased or lower-cased.
If failing a particular validation should prevent later validators from firing, pass boolean TRUE as the second parameter:
If you are using a string name to add a validator, and the validator class accepts arguments to the constructor, you may pass these to the third parameter of addValidator() as an array: Arguments passed in this way should be in the order in which they are defined in the constructor. The above example will instantiate the Zend_Validate_StringLenth class with its $min and $max parameters:
You can also set many validators at once, using addValidators(). The basic usage is to pass an array of arrays, with each array containing 1 to 3 values, matching the constructor of addValidator(): If you want to be more verbose or explicit, you can use the array keys 'validator', 'breakChainOnFailure', and 'options': This usage is good for illustrating how you could then configure validators in a config file:
Notice that every item has a key, whether or not it needs one; this is a limitation of using configuration files -- but it also helps make explicit what the arguments are for. Just remember that any validator options must be specified in order. To validate an element, pass the value to isValid():
Validators are processed in order. Each validator is processed, unless a validator created with a TRUE $breakChainOnFailure value fails its validation. Be sure to specify your validators in a reasonable order. After a failed validation, you can retrieve the error codes and messages from the validator chain:
(Note: error messages returned are an associative array of error code / error message pairs.) In addition to validators, you can specify that an element is required, using setRequired($flag). By default, this flag is FALSE. In combination with setAllowEmpty($flag) (TRUE by default) and setAutoInsertNotEmptyValidator($flag) (TRUE by default), the behavior of your validator chain can be modified in a number of ways:
For more information on validators, see the Zend_Validate documentation.
Methods associated with validation include:
Custom Error MessagesAt times, you may want to specify one or more specific error messages to use instead of the error messages generated by the validators attached to your element. Additionally, at times you may want to mark the element invalid yourself. As of 1.6.0, this functionality is possible via the following methods.
All errors set in this fashion may be translated. Additionally, you may insert the placeholder "%value%" to represent the element value; this current element value will be substituted when the error messages are retrieved. DecoratorsOne particular pain point for many web developers is the creation of the XHTML forms themselves. For each element, the developer needs to create markup for the element itself (typically a label) and special markup for displaying validation error messages. The more elements on the page, the less trivial this task becomes. Zend_Form_Element tries to solve this issue through the use of "decorators". Decorators are simply classes that have access to the element and a method for rendering content. For more information on how decorators work, please see the section on Zend_Form_Decorator. The default decorators used by Zend_Form_Element are:
Since the order in which decorators are registered matters- the first decorator registered is executed first- you will need to make sure you register your decorators in an appropriate order, or ensure that you set the placement options in a sane fashion. To give an example, here is the code that registers the default decorators: The initial content is created by the 'ViewHelper' decorator, which creates the form element itself. Next, the 'Errors' decorator fetches error messages from the element, and, if any are present, passes them to the 'FormErrors' view helper to render. If a description is present, the 'Description' decorator will append a paragraph of class 'description' containing the descriptive text to the aggregated content. The next decorator, 'HtmlTag', wraps the element, errors, and description in an HTML <dd> tag. Finally, the last decorator, 'label', retrieves the element's label and passes it to the 'FormLabel' view helper, wrapping it in an HTML <dt> tag; the value is prepended to the content by default. The resulting output looks basically like this:
For more information on decorators, read the Zend_Form_Decorator section.
Methods associated with decorators include:
Zend_Form_Element also uses overloading to allow rendering specific decorators. __call() will intercept methods that lead with the text 'render' and use the remainder of the method name to lookup a decorator; if found, it will then render that single decorator. Any arguments passed to the method call will be used as content to pass to the decorator's render() method. As an example: If the decorator does not exist, an exception is raised. Metadata and AttributesZend_Form_Element handles a variety of attributes and element metadata. Basic attributes include:
Form elements may require additional metadata. For XHTML form elements, for instance, you may want to specify attributes such as the class or id. To facilitate this are a set of accessors:
Most of the time, however, you can simply access them as object properties, as Zend_Form_Element utilizes overloading to facilitate access to them:
By default, all attributes are passed to the view helper used by the element during rendering, and rendered as HTML attributes of the element tag. Standard ElementsZend_Form ships with a number of standard elements; please read the Standard Elements chapter for full details. Zend_Form_Element MethodsZend_Form_Element has many, many methods. What follows is a quick summary of their signatures, grouped by type:
ConfigurationZend_Form_Element's constructor accepts either an array of options or a Zend_Config object containing options, and it can also be configured using either setOptions() or setConfig(). Generally speaking, keys are named as follows:
Exceptions to the rule include the following:
As an example, here is a config file that passes configuration for every type of configurable data:
Custom ElementsYou can create your own custom elements by simply extending the Zend_Form_Element class. Common reasons to do so include:
There are two methods typically used to extend an element: init(), which can be used to add custom initialization logic to your element, and loadDefaultDecorators(), which can be used to set a list of default decorators used by your element. As an example, let's say that all text elements in a form you are creating need to be filtered with StringTrim, validated with a common regular expression, and that you want to use a custom decorator you've created for displaying them, 'My_Decorator_TextItem'. In addition, you have a number of standard attributes, including 'size', 'maxLength', and 'class' you wish to specify. You could define an element to accomplish this as follows:
You could then inform your form object about the prefix path for such elements, and start creating elements:
The 'foo' element will now be of type My_Element_Text, and exhibit the behaviour you've outlined. Another method you may want to override when extending Zend_Form_Element is the loadDefaultDecorators() method. This method conditionally loads a set of default decorators for your element; you may wish to substitute your own decorators in your extending class:
There are many ways to customize elements. Read the API documentation of Zend_Form_Element to learn about all of the available methods.
|
|