Zend_Form was a big step forward with the 1.5 release; it provided a number of things that simply worked out of the box:
- Filtering against XSS attacks
- Form output
That said, it came with several problems:
- Since validation and filtering were integrated into the form, there was no way to push that to the domain model easily; many developers found they were needing to duplicate validation and filtering efforts.
- This is largely due to the fact that validation/filter chains are attached to individual elements, and not the form itself, making aggregation of all rules difficult.
- The decorators, while powerful and flexible, (a) are also difficult to explain to new users, and (b) can pose new difficulties to the end-user (what precedence is taken? how do I alter output of this decorator? why does this one allow wrapping in HTML tags, and this one does not? etc.)
The chief goals of this RFC for refactoring Zend\Form are:
- Separate validation/normalization from the form object hierarchy; forms should consume validation/normalization chains only, and only for purposes of error reporting.
- Move view-related functionality – aka, the decorators – to the view layer, and make the functionality more declarative/programmatic.
- Forms, subforms, and elements would primarily be value objects. Forms would contain subforms and elements, and metadata describing the form. Elements would contain their value, and then metadata describing the element.
Forms will aggregate:
- Form metadata (action, method, id, etc.)
- Elements and other forms (i.e., subforms)
- Validation/Normalization chains (input filters)
It's unusual to validate an element in isolation. As such, validation chains should be attached only to the form.
- MUST allow detaching/attaching validation/normalization chains, hereafter titled "input filters"
- MUST allow defining a tree of elements (i.e., (nested) subforms of elements)
- MUST allow retrieving a tree of error messages
- MUST allow passing element-specific error messages to that element
- MUST allow partial validations
- SHOULD allow indicating which specific elements must be valid
- COULD allow form elements to hint which validators/filters are desired, e.g., via annotations; a directive would then tell the form to use this data when retrieving the input filter.
In practice, the input filters would operate similarly to Zend\Filter\Input, though the goal is to provide a more programmatic API as well as a factory for generating the chains. Additionally, the chains for individual elements should be detachable.
The desired outcome is something like this:
Decorators are an elegant way to render elements. However, they are also very difficult to teach, particularly to developers not familiar with design patterns. (It also doesn't help that the implementation is mis-named; they more accurately follow the Visitor pattern.)
An additional problem in ZF1 is that developers and/or designers often want very fine-grained control of the output, making the decorators a poor fit.
My proposal is to instead create new and/or modify existing form view helpers. These would consume the form and/or element metadata in order to create output; a given object could be passed to several helpers to create compound output when desired. As a simple example:
A view helper per general form input type will be provided, along with "generic" view helpers that will introspect the type and proxy to the appropriate specific view helper.
"Wait, this looks like a lot of work!" I hear some saying. However, using the lesson from decorators, repitition can be easily addressed: create helpers for common combinations:
and the above would be used like this within a view script:
The goal for ZF2 is to provide a basic set of these "combination" helpers that can be used to accomplish basic form markup with minimal effort by developers. For anything more complex or specific, developers will need to write their own helpers and/or turn to third party modules.