The first thing I was tasked with after I moved full time to the Zend Framework team (17 years ago! Yikes!) was to create a forms library.
Like all the work I did for ZF in the early days, I first created a working group, gathered requirements, and prioritized features.
There were a lot of requests:
- Ability to normalize values
- Ability to validate values
- Ability to get validation error messages
- Ability to render html forms, and have customizable markup
- Ability to do nested values
- Ability to handle optional values
- Ability to report missing values
and quite a lot more.
But those are some of the things that stuck out that I can remember off the top of my head.
Zend_Form was considered a big enough new feature that we actually bumped the version from 1.0 to 1.5 to call it out.
And, honestly, in hindsight, it was a mistake.
A mistake?
Considering the timeframe when I was developing Zend_Form, it was actually a good effort, and it’s still one of those features that folks tell me sold them on the framework.
But within a year or two, I was able to see some of the drawbacks.
I first realized the issues when we started integrating the Dojo Toolkit with ZF.
We ended up having to create first a suite of Dojo-specific form elements, and second a whole bnch of Dojo-specific decorators, which were what we used to render form elements.
While the library gave us this flexibility, I saw a few issues:
-
Duplication.
We had multiple versions of the same form elements, and it was actually possible to get the wrong version for your form context.
And with duplication comes increased maintenance: any time we fixed an issue in one element, we had to check to see if the same issue existed with the Dojo versions, and fix them there as well. -
Javascript.
One of the reasons for integrating Dojo was to allow doing fun things like client-side validation; this allowed giving early feedback, without a round-trip to the server.
But this also meant that we had validation logic duplicated between the server-side and client-side logic.
And more interestingly: the form might be sent as a request by javascript, instead of a standard form request, which meant that we needed to validate it only, and then serialize validation status and messages.
Basically, all the rendering aspects of the form were irrelevant in this scenario.
Which brings me to… -
APIs.
Around this time, APIs started trending.
It would be a few years before REST became popular and commonly understood by developers, but folks were starting to see that we’d be needing them for the nascent mobile application markets, and that they were going to be a useful way to conduct business-to-business transactions.
Once you start having APIs in the mix, a library centered on web forms becomes less interesting.
By the time we started planning for version 2 of ZF, we realized we’d need to reconsider how we did forms.
The first step we took was splitting the validation aspect from the form aspect, and created Zend\InputFilter
to address the first, and Zend\Form
to address the second.
Input filters encapsulated how to filter, normalize, and validate incoming data.
Forms composed an input filter, and then provided hints for the view layer to allow rendering the elements.
This separation helped a fair bit: you could re-use input filters for handling API or JS requests easily, while the form layer helped with rendering html forms.
But I still feel we didn’t get it right:
- Our validation component and our input filter component were each stateful.
When you performed validation, each would store the values, validation status, and validation messages as part of the state.
This makes re-use within the same request more difficult (it was not uncommon to use the same validator with multiple elements, and this now required multiple instances), makes testing more difficult, and makes it harder to understand if the instance represents the definition, or the results of validation. - The longer I’ve worked in web development, the more I’ve realized that while the html generation aspects of these form libraries are useful for prototyping, they inevitably cannot be used for the final production code.
Designers, user experience experts, and accessibility developers will each want different features represented, and these will never fall into the defaults the framework provides.
Even if the framework provides customization features, the end result is more programming effort.
It’s almost always better to code the html markup in your templates, and then feed state (e.g., element IDs
Truncated by Planet PHP, read more at the original (another 7939 bytes)