- Refactor Form view helpers to accept form/element/group objects
- Use PubSub as basis for Decorator Chains
- Use PubSub as basis for Filter and Validation Chains
- Allow retrieving and setting all element validators and filter chains
- Make the metadata/behavior separation exlicit
- No IDs by default
- BC Concerns
Zend_Form has been accused of violating the principal of separation of concerns, due to the fact that it has Model-related logic (filtering and validation, metadata), as well as View-releated logic (rendering, decorators).
While Form objects may be used to provide validation to domain models, many do not like this linking of concerns, and would prefer the ability to attach validation chains from models to the form in order to provide validation error hinting; at the same time, many others feel that forms as simply collections of elements with no ability to validate makes them basically worthless.
Finally, the decoration system, while powerful and flexible, is also quite difficult for many to learn. Having it coupled to Zend_Form causes some issues, as it basically inverts the decorator principal, and is somewhat misnamed as it primarily acts as a filter chain.
Currently, we use the ViewHelper decorator with most form elements as the first decorator. While this works well, it also complicates the issue when you want to build your markup manually; you are forced to use the ViewHelper decorator if you want to use a view helper to render the element.
One simple way to solve this is to modify the individual form*() view helpers to accept elements (or other Zend_Form objects), then we can simplify things greatly. As an example:
If we use the pubsub's filter() method, we can achieve the same effect as the current decorators. As an example:
We would provide some pre-formulated chains as part of this initiative. This would then entail simply setting the view and passing in the element.
The above promotes re-use of decorator chains with multiple elements, and also re-use of pre-defined chains.
The actual act of rendering would then be removed from Zend_Form itself.
If we use the pubsub's filter() method, we have all the functionality of the current Zend_Filter and Zend_Validate chains. This can allow us to detach chains or attach chains. As such, we would define chains and attach them to the form elements.
This allows us to continue to perform validation and filtering as before, but offloads much of the code and functionality to other, reusable components.
In order to achieve full separation, we would need the ability to retrieve these for the entire form for re-use in Models to validate data sets, as well as to pull from Models in order to attach to Forms. In essence, we're talking about an update to Zend_Filter_Input.
The basics would work as follows:
The object structure would look as follows:
and would be used (roughly) as follows:
The various classes in Zend_Form basically contains metadata and behavior. The metadata is typically consumed by decorators in order to determine how to render themselves; the behavior is generally related to validation and/or error message retrieval (which is a related task).
As such, we propose that all Form classes will define a "metadata" property that will contain key/value pairs, and a set of setter/getter methods for the metadata (with specific setters for metadata that requires normalization).
As an example:
Currently, the various Zend_Form elements all generate IDs. With modern JS libraries, this is typically unnecessary, and having explicit IDs makes it very difficult to have forms with variable numbers of the same element or group of elements. Removing ID generation would solve a number of UI issues. (Note: IDs could be set manually as metadata; alternately, setName() could be overridden in order to set the ID as well.)
Translation should be moved to the view layer. The View and Decorator chains would receive the Translator object and use it to translate appropriate labels and metadata. As such, the form, its elements, and the individual validator and validator chains would need no such knowledge of this information.
Since the chains would be separate objects, and the interaction with those chains would no longer be part of the various Form objects, creation of the chains from configuration will no longer be possible.
One way to mitigate this would be to have a "form builder" class that can build the Form objects and all related objects from configuration. Decorators would be one of the exceptions to this, as the Decorator chains would no longer be contained within the various Form objects. As such, a "decorator chain" builder could be useful.
If metadata is moved to an explicit "metadata" container, this may cause problems with existing configuration. A legacy builder class could alleviate this problem, however.
Removing IDs may have UI implications. In particular, the Dojo integration relies heavily on the IDs in order to work. As such, this feature may need to be configurable.