模型/视图/控制器模型中验证的最佳位置?
Posted
技术标签:
【中文标题】模型/视图/控制器模型中验证的最佳位置?【英文标题】:Best Place for Validation in Model/View/Controller Model? 【发布时间】:2011-07-15 10:04:23 【问题描述】:我正在开发一个广泛使用 MVC 设计模式的 php 项目。我希望在表单中添加验证,并且很好奇验证的正确位置是什么。
由于表单的生成方式,对回发数据的验证要简单得多,并且在视图组件中重复性更少。让视图验证响应数据是否可以接受,还是应该在控制器甚至模型中实现?
有什么好处?
【问题讨论】:
【参考方案1】:验证的正确位置是模型。
这是最有意义的,因为您正在对数据进行验证,这就是模型所代表的内容。就 CRUD 更新而言,应该始终以某种方式使用该模型。
如果您要从 看,你应该有验证 被检查。
如果您有更改的控制器 数据,你应该有验证 被检查。
最后,如果您有 模型本身改变数据,你 应该还有验证。
实现这种状态的唯一方法是让验证进入模型。
由于性能和更快的响应,在模型中实现验证后,您应该尝试添加某种客户端(JS)以立即通知最终用户。
验证始终与数据有关。为什么要验证数据?因此,您可以保持存储信息的完整性。在模型级别进行验证允许数据在理论上总是正确的。这始终是必需品。从那里,您可以在业务逻辑和客户端中添加额外的验证,以使您的应用程序更加用户友好。
【讨论】:
这就是 Yii 所做的,而且效果很好。他们也有“验证场景”,所以你可以针对不同的场景有不同的验证规则,比如create vs update 如果“应用程序逻辑”/“使用故事”和“域模型”之间没有区别,那么在模型中进行验证对我来说看起来很实用。否则,AbiusX 建议放入 Application Controller 更有意义。问题是“应用程序控制器”和“GUI 控制器”是不同的概念。简而言之,架构决策应该决定这个问题的答案。 完全同意这个答案。这个设计方面是贫血与丰富领域模型讨论的一个子集。而这个特定的例子可能是最好的指出为什么贫血的领域模型直接违反 DRY,以实际的方式(不仅仅是理论上,正如贫血的倡导者经常指出的那样)【参考方案2】:如果您在客户端验证数据(即 javascript 验证),这绝对不够而且根本不安全,您应该在 View 中实现它。
如果您在服务器端验证数据,并且您的验证不需要应用程序业务逻辑(即您没有检查用户帐户中是否有足够的信用),您应该在控制器中进行验证。
如果验证需要业务逻辑,在模型内部实现,通过控制器调用。
回发验证不好,因为它会带来很多压力和延迟,唯一的好处是对程序员(不计入)。
您可以使用正则表达式进行大部分验证,它在 PHP 和 JS 上具有(几乎)相同的语法。
【讨论】:
我被教导要使控制器尽可能轻。在我看来,验证是业务逻辑的一部分...... 在您的示例中,重复的用户名是应用程序逻辑的一部分。但是控制器可以检查用户名中的无效字符。 控制器应该很轻,但由于验证是强制性的,所以不能跳过。减轻控制器意味着不将任何逻辑或视图放入其中。 MVC 中的控制器是表示层的一部分。他们不应该知道如何执行数据验证,这是模型层的职责。 不是这样的。您的意思是 UI 不应该能够告诉用户他们是否输入了名称而不是数字?它与应用程序的业务逻辑无关。这更像是一个演示问题。电子邮件输入是一个演示问题,而不是业务逻辑问题(也可以在那里重新检查)【参考方案3】:模型中的验证似乎是最常见的方法(您最终会得到类似 $obj->isValid()
的东西),这适用于许多情况。
但是,根据您的用例,可能有充分的理由在模型之外执行验证,无论是使用单独的验证代码还是在控制器中等:
如果整体验证问题的大部分涉及模型无法访问的信息(例如,如果管理员用户可以执行普通用户无法执行的转换,或者某些属性在特定日期之后无法更改),那么您可能需要在同一个地方检查所有这些约束。 在为测试构建对象时,应用非常宽松的验证规则也可能很方便或有必要。 (“购物篮”对象通常可能需要关联用户,而该用户又需要有效的电子邮件地址等。100% 有效的购物篮对象可能不方便在购物篮单元测试中构建。) 由于历史原因,验证规则可能会发生变化(例如,在以前不需要的情况下强制执行“性别”),因此您最终可能会得到需要区别对待的不同版本的数据。 (不同的验证规则也可能适用于批量数据导入。) 如果验证非常复杂,您可能希望根据对调用者最有用的内容提供不同的错误消息(或根本不提供)。在其他情况下,true
或 false
可能就足够了。
也许可以通过模型的 isValid()
方法的参数来处理这些不同的用例,但是随着验证样式数量的增加,这变得越来越笨拙。 (而且我确实认为几乎可以保证,单一的“一刀切”isValid()
方法最终将证明对于大多数非平凡项目来说是不够的。)
【讨论】:
自从我发布这个问题以来已经有一段时间了,但我从经验中了解到,将模型分成两个单独的部分更容易维护模型。业务模型层应该应用所有“业务”规则,例如在以前不需要的地方强制执行“性别”。可以更改业务模型以在所有新应用程序/更新/等上要求“性别”。服务模型层不关心“业务”规则,而是必须验证数据完整性等。因此可以独立测试服务层和业务层。我在我的博客中写过这个...... leahayes.wordpress.com/2011/04/21/…【参考方案4】:不要混淆使用验证来清理或清理发布的值。您应该通过从 Controller 中的值中删除任何恶意元素来获取发布的值并清除它们。然后将数据发送到模型以验证预期值或格式。通过将这些操作分为两个过程,可以降低实施恶意代码的风险。如果您使用“不信任任何人输入”策略,此方法效果很好;知道一些程序员可能会变得草率或懒惰。另一个积极的方面是防止你的模型变得臃肿和过度工作,如果是这样,那么使用模型助手来完成肮脏的工作。这种方法还有助于平衡您的应用程序负载并提高性能。
【讨论】:
以上是关于模型/视图/控制器模型中验证的最佳位置?的主要内容,如果未能解决你的问题,请参考以下文章
在 Laravel 中,直接从视图向模型或控制器请求一些数据的最佳方式是啥?
iOS - 为帖子 + 评论数据模型设置视图控制器的最佳实践是啥?
KVO 在 UITableView 中观察模型变化的最佳实践