在 Symfony Form 中通过 empty_data 选项定义如何创建表单绑定的对象

在 Symfony Form 中通过 empty_data 选项定义如何创建表单绑定的对象

Chris Yue No Comment
Posts

对于大部分 Symfony Form 的新手来说,可能是 Symfony 入门文档并没有写得很详细的原因,为了要使用 Form 的数据自动绑定功能,只能将绑定 Form 的对象的类构造函数去掉,改用 setter,因为这是 Form 默认绑定数据的方式。然而这么做可能的确是解决了表单绑定的问题,但却修改了类定义,而类的定义是代码设计思路的体现。

我把做事分三个阶段:1. 把事做完;2. 把事做对;3. 把事做好。我认为一旦决定做一件事情至少都应该要求自己把这个事情做对,也就是我们常说的“专业”。

而不专业的工程师,大都很容易会因自己所使用的工具而妥协代码的设计。对于一个对象来说,构造函数的作用,不仅仅是初始化对象那么简单。从代码设计的角度来说,构造函数的参数,即使对象的『必要属性』,或者非 null 属性,从代码层面上,强制调用者必须先准备好此对象的『必要属性』的数据。

如果一个类的某个属性,只对应了某个 setter 而非构造函数里的参数,则可以认为此属性是此类可为 null 的。如果将本来是必要的属性都改成使用 setter,其他人使用这个类的时候,就有可能出现意想不到的问题。

另外,一个对象属性,只要有与之对应的 setter,意味着此属性是可写的。如果一个对象包含了只读属性,就不应该存在对应的 setter。

以我开发的经验,代码设计必然比所使用的工具要重要。如果代码设计与我们所使用的工具发生了矛盾,先停下来仔细想想,怎么做才是对的,如果工具破坏了本来是对的代码设计,那宁愿放弃此工具,而保证代码设计的正确性,可靠性。

而另一方面,完善的第三方工具,是一定会考虑各种代码设计的。其实 Symfony 的 Form 也是支持对象的构造函数的,只不过需要你深入文档或者代码。其实,如果用的工具或者第三方库,用的人比较多,那一定有它的道理。很有可能你的问题已经被解决了,只不过你需要花更多的时间去寻找答案。

说了那么多,举个例子,假如我们有一个用户类 User,需求要求是用户名不可修改,密码可改,并且用户必须有密码和用户名,那么此 User 类很显然,设计成这样才能算『对』:

关于构造函数的问题,UserType 可使用 Form 的 empty_data 选项来解决:

深入 Symfony Form 的执行代码,不难发现,如果 Form 包含 empty_data 选项,当 Form 没有绑定对象的时候,将按照 empty_data 选项所配置的方法去生成对象,否则将通过 ‘default_class’ 选项直接尝试 new 一个新对象。

我们再举出另外一个例子:用户可以新建若干自己的移动电话,那么移动电话类应该是这个样子:

可以看到,Mobile 如果没有 $user$number,是没有存在的意义的,这体现在了构造函数上;另外,$user 应该是不能被修改的,所以 $user 没有 setter。

那么接下来看 MobileType 如何设计。

首先,对于『用户可以设置自己的移动电话』这个需求来说,MobileType 不应该出现 user,因为 user 必须是当前访问用户自己,索性不加 user 这个字段,完全杜绝普通用户可以把自己的移动电话转给其他人的可能性。

我们先给 MobileType 只添加上 number 属性:

至于$user在何时注入到Mobile类的构造函数中,其实我们也有很多选择,比如,在控制器里去设置:

或者,直接在 MobileType 里注入 user 对象,然后在 MobileType 里定义 empty_data 属性:

两种做法都能达成一样的目的,但却不都是“对”的做法。分析这两个种方式,本质上的不一样是 Mobile 的创建是让 MobileType 负责还是让控制器自己负责。我的观点是:控制器只负责操作 Form,而 Form 应该负责 Model 的创建,按照这种思路最直观的优势,如果有多个控制器都使用此 Form,就不用一遍又一遍在控制器里定义 empty_data

另外,此 Form 也应该可以用在编辑上,但编辑的时候,$user 参数变得毫无意义,我们可以将上面的代码做以下改进:

当控制器使用此 Form 来创建新 Mobile 时,需要传入 $user,而编辑 Mobile 的时候,不需要传入 $user,that makes sense too。当然,还可以通过 $user 属性是否为 null,来判断是否还需要设置 empty_data 属性。

总之,今天主要是为了抛出代码设计重要性的话题,这是一个大坑,却也是代码最美妙的地方。

在 Symfony Form 中通过 empty_data 选项定义如何创建表单绑定的对象 by Chris Yue is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.

微信赞赏码

文章不错,我要帮站长分担建站费!
天使投赏人

发表评论

99 − 93 =