表单处理的问题在于它违反了 MVC 的定义。这是一个被称为“横切”的问题,过去已经被科学研究过。例如,论文Domain Driven Web Development With WebJinn是关于该主题的有趣读物。
例如,考虑表单与 MVC 不同层的关系:
模型:
- 表单复制了域模型 (DM) 的信息结构。如果您更改此结构(例如,通过向数据结构添加字段或向过程添加参数),您还必须调整表单以输入该信息。
- 他们需要来自您的 DM 的类型信息,以将输入转换为那里所需的类型。
- 他们需要知道您的 DM 中指定的约束以验证输入。
- 理想情况下,它们直接从/向您的 DM 读取和写入数据(例如,通过读取/写入数据结构的字段或通过使用提交的值作为参数调用 DM 中的过程)。
控制器:
- 表单接收提交的数据并将其发送给 DM。
- 他们根据是否成功验证来改变程序流程。
看法:
- 表单呈现为 HTML 标记和属性的复杂结构,依赖于上述所有内容(是否需要字段?是否应显示错误?如何对字段进行排序?在下拉列表中提供哪些选择?等)
因此,不可能编写一个不涉及所有这些层的表单抽象机制。相反,解决方案是根据 MVC 将表单库本身构造成满足 SRP 的不同层和子组件。如果您查看 Symfony2 表单组件,它做得非常好。;)
那么为什么它会是这样一个“巨大的可怕野兽”呢?第一个问题是抽象问题。例如,考虑一个简单的下拉菜单。如果我们想重用下拉菜单的代码,我们需要以某种方式抽象它。现在检查上面的列表,即使是这个简单的输入也触及了 MVC 应用程序的所有三层。你怎么能抽象出要被构造成三个不同部分的东西呢?
第二个问题是特征多样性。表单库永远无法解决开发人员在日常生活中面临的所有问题。因此,所有这些层和抽象机制都需要可扩展,以便您可以使它们的行为完全符合您的要求。
虽然是可扩展的,但 Form 组件已经解决了数百个您甚至不必再考虑的小问题。如何输入日期,如何使用不同的 UI(下拉菜单、复选框、单选按钮等)选择一个或多个选项列表,如何再次保护表单安全漏洞等等都是我可以写论文的主题关于。
您会看到表单库变得非常复杂。在编写此类“巨大的可怕野兽”时,我们最好的选择是让他们的 API 对于初学者来说尽可能简单,对于更高级的用户来说尽可能灵活,并编写关于充分利用其全部功能的大量文档。最后一点肯定仍然缺乏(请帮助!),但我们一直在努力解决上述所有问题。
另一方面,不幸的是,将复杂问题简化为简单问题是不可能的。
那么其他更简单的表单库呢?在我看来,这些甚至都没有尝试解决 Symfony2 表单组件已经为您解决的大多数问题。:)
2014 年 1 月 24 日更新:对于任何想了解更多(更多)的人,这是我发表的一篇关于该主题的论文。