在设置每个属性时验证域实体,或者稍后再验证所有属性?

时间:2021-06-29 15:51:25

When validating a domain entity, is it better to validate the values as they are set, or all at once with a validator (such as in Symfony2) later on?

验证域实体时,最好在设置时验证值,还是稍后使用验证器(例如在Symfony2中)验证值?

For example:

Option 1. Validate while being set

选项1.设置时验证

public function setEmail($email)
{
    if(!filter_var($email, FILTER_VALIDATE_EMAIL)) {
        throw new EntityException('The specified email address ' . $email . ' is invalid.');
    }

    $this->_email = $email;
    return $this;
}

Option 2. Validate later...

选项2.稍后验证......

$user = new UserEntity();
$user->setEmail('johnnie@duh.com');
$validator = new Validator();
$validator->validate($user);

Option 3. Both of the above (although seems a little redundant and not worth the overhead).

选项3.以上两者(虽然看起来有点多余,不值得开销)。

I know that the first one probably makes for more airtight entities, but the second one makes for more user friendly error handling.

我知道第一个可能会产生更多的密闭实体,但第二个实现了更加用户友好的错误处理。

Also, the second option seems easier to configure and maintain...as I don't have to adjust the setters, and I can centralize my validation logic to a single class.

此外,第二个选项似乎更容易配置和维护...因为我不必调整setter,我可以将我的验证逻辑集中到一个类。

What it boils down to...
So basically, it sounds like Option 2 is what I WANT to do, but feel like sacrificing the airtight-ness of the entity (for example, if I forget to run the entity through the validator), might be stupid.

它归结为......基本上,听起来像选项2是我想要做的,但感觉就像牺牲了实体的气密性(例如,如果我忘记通过验证器运行实体),可能是愚蠢的。

2 个解决方案

#1


2  

Single Responsibility Principle

单一责任原则

The best is to have all necessary validations in a separated layer. With that will be easier to maintain and test the validators. Also easier to validate data across your application.

最好的方法是在分离的层中进行所有必要的验证。这将更容易维护和测试验证器。还可以更轻松地验证应用程序中的数据。

Don't Repeat Yourself

不要重复自己

You don't have to call validate() for each entity.

您不必为每个实体调用validate()。

All you have to do is to implement the validation on your repository layer or service layer if you have one.

您所要做的就是在存储库层或服务层上实现验证(如果有)。

$user = new User();
// [...]
$user->setEmail('myinvalidemail#blah,com');
$repository->save($user);

So in your user's repository

所以在你的用户的存储库中

UserRepository extends AbstractRepository {}

And the common validation for all entities:

以及所有实体的通用验证:

abstract class AbstractRepository {
    public function save($entity) {
        $validator = // Get your validator based on the entity's name or something else
        $validator->validate($entity); // Throws exceptions or flag the  fields for future use

         // Now save it...
    }
}

#2


2  

There are doubtless going to be situations where validation is unnecessary at the application level (i.e., you know you are working with valid data at a particular point). Although there's nothing wrong with applying validation in these cases, it's certainly superfluous.

毫无疑问,在应用程序级别不需要验证的情况下(即,您知道您正在使用特定点的有效数据)。虽然在这些情况下应用验证没有任何问题,但它肯定是多余的。

In addition, you might find yourself in a scenario where you want to perform a "mass validation" of incoming data. This would likely apply more to a service or to custom-implemented forms where you don't have e.g., Symfony's form validation framework to fall back on.

此外,您可能会发现自己处于要对传入数据执行“批量验证”的情况。这可能更适用于服务或自定义实现的表单,而您没有例如Symfony的表单验证框架。

These would tend to indicate that Option 2 is the more desirable way to go, perhaps with caveat that the validator should be invoked automatically when attempting to persist the object (e.g., during the model's pre-save event; I'm not familiar with Doctrine 2 yet, but Doctrine 1.2 does have its own validation framework that can accomplish this).

这些往往表明选项2是更理想的方式,可能需要注意的是,在尝试持久化对象时应该自动调用验证器(例如,在模型的预保存事件期间;我不熟悉Doctrine 2但是,Doctrine 1.2确实有自己的验证框架可以完成这个任务。

Having invalid data is surely never a desirable scenario, but so long as you can be assured that invalid data are not persisted, this gives you the freedom to trust that any data you pull from the database are valid (note that I say "valid" here, not "trustworthy"!).

拥有无效数据肯定不是理想的情况,但只要您可以确信无效数据不会被保留,这使您可以*地相信从数据库中提取的任何数据都是有效的(请注意,我说“有效”)在这里,不是“值得信赖”!)。

#1


2  

Single Responsibility Principle

单一责任原则

The best is to have all necessary validations in a separated layer. With that will be easier to maintain and test the validators. Also easier to validate data across your application.

最好的方法是在分离的层中进行所有必要的验证。这将更容易维护和测试验证器。还可以更轻松地验证应用程序中的数据。

Don't Repeat Yourself

不要重复自己

You don't have to call validate() for each entity.

您不必为每个实体调用validate()。

All you have to do is to implement the validation on your repository layer or service layer if you have one.

您所要做的就是在存储库层或服务层上实现验证(如果有)。

$user = new User();
// [...]
$user->setEmail('myinvalidemail#blah,com');
$repository->save($user);

So in your user's repository

所以在你的用户的存储库中

UserRepository extends AbstractRepository {}

And the common validation for all entities:

以及所有实体的通用验证:

abstract class AbstractRepository {
    public function save($entity) {
        $validator = // Get your validator based on the entity's name or something else
        $validator->validate($entity); // Throws exceptions or flag the  fields for future use

         // Now save it...
    }
}

#2


2  

There are doubtless going to be situations where validation is unnecessary at the application level (i.e., you know you are working with valid data at a particular point). Although there's nothing wrong with applying validation in these cases, it's certainly superfluous.

毫无疑问,在应用程序级别不需要验证的情况下(即,您知道您正在使用特定点的有效数据)。虽然在这些情况下应用验证没有任何问题,但它肯定是多余的。

In addition, you might find yourself in a scenario where you want to perform a "mass validation" of incoming data. This would likely apply more to a service or to custom-implemented forms where you don't have e.g., Symfony's form validation framework to fall back on.

此外,您可能会发现自己处于要对传入数据执行“批量验证”的情况。这可能更适用于服务或自定义实现的表单,而您没有例如Symfony的表单验证框架。

These would tend to indicate that Option 2 is the more desirable way to go, perhaps with caveat that the validator should be invoked automatically when attempting to persist the object (e.g., during the model's pre-save event; I'm not familiar with Doctrine 2 yet, but Doctrine 1.2 does have its own validation framework that can accomplish this).

这些往往表明选项2是更理想的方式,可能需要注意的是,在尝试持久化对象时应该自动调用验证器(例如,在模型的预保存事件期间;我不熟悉Doctrine 2但是,Doctrine 1.2确实有自己的验证框架可以完成这个任务。

Having invalid data is surely never a desirable scenario, but so long as you can be assured that invalid data are not persisted, this gives you the freedom to trust that any data you pull from the database are valid (note that I say "valid" here, not "trustworthy"!).

拥有无效数据肯定不是理想的情况,但只要您可以确信无效数据不会被保留,这使您可以*地相信从数据库中提取的任何数据都是有效的(请注意,我说“有效”)在这里,不是“值得信赖”!)。