【问题标题】:Validate form input in Domain Objects setters?验证域对象设置器中的表单输入?
【发布时间】:2013-02-09 01:30:01
【问题描述】:

自从我开始学习 MVC 以来,我一直在我的控制器中验证我的表单数据,这是我在浏览 CodeIgniters 代码时养成的习惯,但我了解到它执行某些操作的方式并不是最好的,它只是完成工作。

所有表单数据都应该由域对象验证吗?如果是这样,它应该像这样在二传手中完成

public function setFirstName($firstName) {

    // Check if the field was required
    if(!$firstName) {
        throw new InvalidArgumentException('The "First name" field is required');
    }

    // Check the length of the data
    // Check the format 
    // Etc etc
}

另外,例如,如果我正在处理基本用户注册,我的 User 类没有 $confirmPassword 属性,所以我不会这样做

$user->setConfirmPassword($confirmPassword);

检查输入的两个密码是否相等的一种方法是设置$password 并执行类似的操作

$user->setPassword($password);
if(!$user->matchPassword($confirmPassword)) {
    throw new PasswordsNotEqualException('Some message');
}

我认为这将在服务层中完成?

任何可以帮助我朝着正确方向前进的建议都会很棒。谢谢。

【问题讨论】:

  • 我认为 Rails 和 Django 在模型级别做到了这一点,这很有帮助。
  • 他们是按照我上面的方式做的吗?通过在属性设置器中执行此操作并引发异常?
  • @WaleedKhan ,它们甚至都没有实现 MVC。他们甚至没有模型层。只有活动记录实例的集合。
  • @tereško 我在设置器中进行验证是否正确?如果是这样,我是否检查“密码”和“确认密码”字段是否正确?

标签: php oop model-view-controller model validation


【解决方案1】:

所有表单数据都应该由域对象验证吗?如果是这样 是否应该像这样在设置器中完成

IMO 您应该只允许创建有效对象,而实现这一点的最佳方法是在创建对象的方法中进行这些检查。

假设用户的名字不能更改,您将在创建用户时验证它。这样,您就可以忘记 setter,因为您不再需要它了。

在某些情况下,您可能希望更改属性,并且您也需要验证它们(因为如果是这种情况,更改可能会导致从有效对象变为无效对象)。

检查输入的两个密码是否相等的一种方法是 设置 $password 并执行类似...

你可以用同样的方式处理这个问题:有一个 Password 对象,它在创建时检查密码和确认。如果您有一个有效的 Password 实例,则可以在知道它通过了您指定的所有验证后使用它。

参考文献

这些设计原则(从一开始就完整和有效的对象等)来自 Hernan Wilkinson 的“Patagonia 背后的设计原则”。请务必查看ESUG 2010 Videopresentation slides

我最近回答了另一个关于验证属性的问题,我认为您可能会派上用场:https://stackoverflow.com/a/14867390/146124

干杯!

【讨论】:

  • -1:您的“解决方案”提倡三件事之一,正如现在所写的那样:在构造函数中进行验证或在工厂方法中进行验证,或者在域对象之外进行验证。而且,如果它是前两个之一:那么这是有害的做法。如果是后者,那么它就不再是域对象了。
【解决方案2】:

TL;DR

不,setter 不应该验证数据。而 nick2083 是完全错误的。

加长版...

根据 Tim Howard 提供的定义 [source]domain objects 可以验证它们包含的域信息的状态。这基本上说明,要让您真正拥有一个域对象,该对象需要能够验证自己。

何时验证

你基本上必须选择:

  • 在每个 setter 中验证
  • 有一种方法可以验证整个对象

如果验证是 setter 的一部分,则存在一个主要缺点:setter 的顺序很重要。

示例:假设您正在制作一个涉及人寿保险的应用程序。很有可能,当触发保单时(被保险人死亡),您将拥有一个域对象,其中包含被保险人和获得保费的人。您必须确保收件人和被保险人不是同一个人。但是没有规则可以控制执行 setter 的顺序。

当您在域对象中有两个或多个参数时,必须相互验证,实现变得有点模糊。最可行的解决方案是检查何时分配了所有参数,但此时您已经失去了 in-setter 验证的好处:代码的执行已经移过了无效数据的来源。

如果参数 B 很大,那么 21 并且 C 已经设置,那么域对象的有效状态没有设置参数 A,您将如何处理?

结论: setter 中的验证只是可行的解决方案,当您拥有非常简单的域对象且没有纠结的验证规则时。

【讨论】:

  • 还有 .. 你对抛出异常的痴迷是什么?
  • 您在帖子顶部说“setter 不应该验证数据”,然后您说我有两个验证选项,其中一个是“每个 setter 中的验证”,然后在底部说“二传手中的验证只是可行的解决方案”。在今天stackoverflow.com/questions/15050497 的这篇文章中,您说“当您有多个绑定参数时,setter 上的数据验证失败。”你好像一直在说不同的话,难怪我这么糊涂。
  • @David,您(和其他 4 人)是否也阅读了这句话的其余部分?:“setter 中的验证只是可行的解决方案,当您有非常简单的域对象时,没有复杂的验证规则。” 句子是否有某种缺陷?它说:“唯一的情况是,当你没有完全延迟使用 setter 验证时,你的域对象没有纠结的验证规则。”基本上 - 它谈论美化的价值对象。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多