验证域实体时,是按设置验证值更好,还是稍后使用验证器(如Symfony2)一次性验证值更好?
例如:
选项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;
}
选项2。稍后验证
$user = new UserEntity();
$user->setEmail('johnnie@duh.com');
$validator = new Validator();
$validator->validate($user);
选项3。以上两项(尽管看起来有点多余,不值得开销)
我知道第一个可能会使实体更加严密,但第二个可能会让错误处理更加用户友好。
此外,第二个选项似乎更容易配置和维护。。。因为我不必调整setter,而且我可以将验证逻辑集中到一个类中。
归根结底…
因此,基本上,这听起来像是选项2是我想要做的,但我觉得牺牲实体的气密性(例如,如果我忘记通过验证器运行实体)可能是愚蠢的。
毫无疑问,在某些情况下,应用程序级别的验证是不必要的(即,您知道在某个特定点使用的是有效数据)。尽管在这些情况下应用验证没有错,但它肯定是多余的。
此外,您可能会发现自己处于这样一种场景中,您希望对传入数据执行"大规模验证"。这可能更多地应用于服务或自定义实现的表单,而您没有这些表单,例如Symfony的表单验证框架。
这些倾向于表明,选项2是更可取的方法,可能需要注意的是,当试图持久化对象时,验证器应该自动调用(例如,在模型的预保存事件期间;我还不熟悉原则2,但原则1.2确实有自己的验证框架可以实现这一点)。
拥有无效数据肯定不是一种理想的情况,但只要你能确信无效数据不会被持久化,这就让你可以自由地相信你从数据库中提取的任何数据都是有效的(注意,我在这里说的是"有效的",而不是"值得信赖的"!)。
单一责任原则
最好的方法是在一个单独的层中进行所有必要的验证。这样将更容易维护和测试验证器。也更容易在应用程序中验证数据。
不要重复自己
您不必为每个实体调用validate()。
您所要做的就是在存储库层或服务层(如果您有)上实现验证。
$user = new User();
// [...]
$user->setEmail('myinvalidemail#blah,com');
$repository->save($user);
因此,在您的用户存储库中
UserRepository extends AbstractRepository {}
以及所有实体的通用验证:
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...
}
}