当前位置 : 主页 > 手机开发 > 其它 >

DDD,PHP – 在哪里执行验证?

来源:互联网 收集:自由互联 发布时间:2021-06-22
我最近开始玩DDD.今天我遇到了在我的应用程序中放置验证逻辑的问题.我不确定应该拿起哪一层.我在互联网上搜索,无法找到解决我问题的统一解决方案. 让我们考虑以下示例.用户实体由
我最近开始玩DDD.今天我遇到了在我的应用程序中放置验证逻辑的问题.我不确定应该拿起哪一层.我在互联网上搜索,无法找到解决我问题的统一解决方案.

让我们考虑以下示例.用户实体由ValueObjects表示,例如id(UUID),年龄和电子邮件地址.

final class User
{
    /**
     * @var \UserId
     */
    private $userId;

    /**
     * @var \DateTimeImmutable
     */
    private $dateOfBirth;

    /**
     * @var \EmailAddress
     */
    private $emailAddress;


    /**
     * User constructor.
     * @param UserId $userId
     * @param DateTimeImmutable $dateOfBirth
     * @param EmailAddress $emailAddress
     */
    public function __construct(UserId $userId, DateTimeImmutable $dateOfBirth, EmailAddress $emailAddress)
    {
        $this->userId = $userId;
        $this->dateOfBirth = $dateOfBirth;
        $this->emailAddress = $emailAddress;
    }
}

非业务逻辑相关的验证由ValueObjects执行.这没关系.
我在放置业务逻辑规则验证方面遇到了麻烦.

如果,假设我们需要让用户只有18岁才能拥有自己的电子邮件地址呢?
我们必须检查今天的年龄,如果不合适则抛出异常.

我应该把它放在哪里?

>实体 – 在构造函数中创建用户实体时检查它?
>命令 – 在执行插入/更新/任何命令时检查它?我在我的项目中使用战术家,所以它应该是一份工作

>命令
>命令处理程序

在哪里放置负责检查存储库数据的验证器?

像电子邮件的唯一性.我读到了规范模式.如果我直接在Command Handler中使用它,可以吗?

最后但并非最不重要.

如何将其与UI验证集成?

我上面描述的所有内容都是关于域级别的验证.但是让我们考虑从REST服务器处理程序执行命令.我的REST API客户端希望我返回有关输入数据错误时出错的完整信息.我想返回一个包含错误描述的字段列表.
我实际上可以在try块中包含所有命令准备并监听验证类型异常,但主要问题是它会在第一个异常之前向我提供有关单个错误的信息.
这是否意味着,我必须在控制器级复制我的验证逻辑(即使用zend-inputfilter – 我使用的是ZF2 / 3)?这听起来不存在……

先感谢您.

我将逐一回答你的问题,并在这里和那里给我两分钱以及如何解决问题.

Non business logic related validation is performed by ValueObjects

实际上,ValueObjects代表业务领域的概念,因此这些验证实际上也是业务逻辑验证.

Entity – check it while creating User entity, in the constructor?

是的,在我看来,你应该尝试尽可能地在Aggregates中添加这种行为.如果将其放入命令或命令处理程序中,则会导致内聚性和业务逻辑泄漏到应用程序层中.我甚至会走得更远.问自己一个问题,即模型中是否存在未明确的隐藏概念.在你的情况下,它是一个AdultUser和一个UnderagedUser(它们都可以实现UserInterface)实际上有不同的行为.在这些情况下,我总是努力明确地对此进行建模.

Like email uniqueness. I read about the Specification pattern. Is it ok, if I use it directly in Command Handler?

如果您希望能够将复杂查询与逻辑运算符组合在一起(特别是对于读取模型),则规范模式很好.在你的情况下,我认为这是一个矫枉过正.将一个简单的containsUserForEmail($emailValueObject)方法添加到UserRepositoryInterface并从Use Case中调用它很好.

<?php
$userRepository
    ->containsUserForEmail($emailValueObject)
    ->hasOrThrow(new EmailIsAlreadyRegistered($emailValueObject));

How to integrate it with UI validation?

首先,已经应该对相关字段进行客户端验证.以正确的方式轻松使用您的系统,并且难以以错误的方式使用它.

当然还需要服务器端验证.我们目前使用模式验证方法,其中我们有一个中央模式注册表,我们从中获取给定有效负载的模式,然后可以针对该JSON模式验证JSON有效负载.如果失败,我们返回一个序列化的ValidationErrors对象.我们还通过Content-Type:application / json告诉客户端; profile = https://some.schema.url/v1/user# header如何构建有效的有效负载.

您可以在CQRS架构here和here之上找到一些关于如何构建RESTful API的好文章.

网友评论