验证应在哪里进行? [英] Where should validation take place?

查看:95
本文介绍了验证应在哪里进行?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在我的PHP项目中使用MVC模式.我还想对模型层使用Dao-Service模式,因为它使数据库引擎易于互换,并使业务逻辑与数据库交互不受影响.

I want to use MVC pattern in my PHP project. I also want to use Dao-Service pattern for Model layer since it makes database engines easily interchangeable and keeps business logic out of DB interaction.

现在,我听说验证应该在模型层进行,因为控制器仅负责传输数据.那是很合理的.

Now, I heard that validation should happen in Model layer since Controllers are only responsible for transporting data. That's pretty reasonable.

但是,它应该在服务层还是实体本身中实现?

Should it, however, be implemented in Service layer, or entities themselves?

class Post extends Entity
{
    protected $title;

    public function getTitle()
    {
        return $this->title;
    }

    public function setTitle($newTitle)
    {
        if (strlen($newTitle) == 0)
            throw new ValidationException('Title cannot be empty.');
        $this->title = $newTitle;
    }
}

class PostService
{
    public static function saveOrUpdate(Post $post)
    {
        PostDao::saveOrUpdate($post);
    }
}

优点:

  • 我马上知道我做错了什么
  • 一切都在一个地方,这似乎是一件好事.

缺点:

  • 由于花哨的设置者和获取者而产生的许多样板代码,
  • 向实体添加一些业务逻辑,这似乎是一件坏事(特别是如果验证非常复杂-例如,需要查询数据库/其他服务),
  • 序列化和反序列化可能会变得困难.
class Post extends Entity
{
    public $title;
}

class PostService
{
    public static function saveOrUpdate(Post $post)
    {
        if (strlen($post->title) == 0)
            throw new ValidationException('Title cannot be empty.');
        PostDao::saveOrUpdate($post);
    }
}

优点:

  • 保留业务逻辑以进行服务,这似乎是一件好事,
  • 样板保持最小.

缺点:

  • 我不立即知道什么时候出问题了,而什么实际上出了问题.
  • 我无法保证在将验证保存到数据库之前会真正进行验证.一个例子:我必须将帖子保存在两个例程中,忘记在其中一个例程中使用PostService::saveOrUpdate代理,并直接通过PostDao::saveOrUpdate进行操作. of,验证不会在该例程中进行,并且项目的唯一希望是现在进行单元测试或由我自己在代码中发现它.因此,在这方面很难维护代码.
  • I don't know immediately when things go wrong and what did actually go wrong.
  • I have no guarantee that validation will actually take place before saving it to database. An example: I have to save post in two routines, forget to use PostService::saveOrUpdate proxy in one of them and do it directly via PostDao::saveOrUpdate. Poof, validation doesn't take place in that routine and project's only hope are now unit tests or myself spotting it in the code. Thus, code is more difficult to maintain in this regard.

您有什么提示吗?我想念什么吗?到目前为止,该项目尚处于起步阶段,因此我已准备就绪.

Do you have any hints, SO? Am I missing something? So far the project is on drawing board so I'm ready for anything.

推荐答案

注意:控制器不负责传输数据".控制器的职责是更改模型的状态(在特殊情况下,即当前视图实例的状态).

NOTE: Controller is not responsible for "transporting data". Controller's responsibility is altering model's (and in special cases - current view instance's) state.

实际上有第三种方法:为域对象使用单独的isValid()方法(a您称它们为实体").当您具有跨多个数据条目的验证规则时,setter验证就会变得混乱.

There is actually third approach: have a separate isValid() method for the domain object (you call them "entities"). The setter validation becomes messy, when you have validation rules across multiple data entries.

示例:验证用户注册表单的重复密码.

Example: validation of repeated password for user registration form.

在setter中进行验证会变得很混乱.特别是如果您选择对每个失败的验证使用例外.

Having validation in setter for this will turn out quite messy. Especially if you opt to use exceptions for each failing validation.

此外,我会为您推荐数据访问对象使用数据映射器.该代码基本上看起来像这样:

Also, instead of data access objects I would recommend for you to use data mappers. The code would basically look something like this:

$post = new Model\Domain\Post;
$mapper = new Model\Mappers\Post($pdo);

$post->setId(42);
$mapper->fetch($post);

$post->setTitle($title);
if ($post->isValid()) {
    $mapper->store($post);
}

如果您想重用一些验证规则,该方法还允许您通过构造函数在Model\Domain\Post实例中注入某种Validator实例来使验证外部化.

This approach also lets you externalize the validation by injecting some kind of Validator instance in the Model\Domain\Post instance through constructor, if you want to reuse some validation rules.

尽管,当制作一个更大的应用程序时,您可能会注意到,很少有重复检查,这超出了现有的

Though, when making a larger app, you will probably notice, that there are very few repeated checks, which go beyond existing php filters.

注意::请不要使用静态类.这迫使您在不需要的地方使用过程范式.

NOTE: please don't use static classes. This forces you to use procedural paradigm, where it's not needed.

您还需要注意的另一件事是:您正在执行哪种验证?

Another thing that you have to pay attention to is: what kind of validation are you doing ?

应在域对象中验证业务规则,数据完整性检查(例如:此电子邮件地址是否唯一")是持久性逻辑的一部分.持久性逻辑应该(根据 SRP 来处理).在给定的示例中,该部分由数据映射器管理.

Business rules should be validated in domain objects, but data integrity checks (like: "is this email address unique") are part of persistence logic. And persistence logic should (according to SRP be handled by a separate instance. In the given example that part was managed by data mapper.

这篇关于验证应在哪里进行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆