hop*_*sey 6 php validation domain-driven-design model domain-object
我最近开始玩 DDD。今天我在我的应用程序中放置验证逻辑时遇到问题。我不确定我应该选择哪一层。我在互联网上搜索,找不到解决我问题的统一解决方案。
让我们考虑以下示例。用户实体由值对象表示,例如 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;
}
}
Run Code Online (Sandbox Code Playgroud)
与业务逻辑无关的验证由 ValueObjects 执行。没关系。我在放置业务逻辑规则验证时遇到了麻烦。
假设,如果我们需要让年满 18 岁的用户拥有自己的电子邮件地址,该怎么办?我们必须检查今天的年龄,如果不正常则抛出异常。
我应该把它放在哪里?
在哪里放置负责检查存储库数据的验证器?
就像电子邮件的唯一性一样。我阅读了规范模式。可以吗,如果我直接在命令处理程序中使用它?
最后但并非最不重要。
如何将其与 UI 验证集成?
我上面描述的所有内容都是关于域级别的验证。但是让我们考虑从 REST 服务器处理程序执行命令。我的 REST API 客户端希望我在输入数据错误的情况下返回有关出错的完整信息。我想返回带有错误描述的字段列表。我实际上可以在 try 块中包装所有命令准备并侦听验证类型异常,但主要问题是它会为我提供有关单个错误的信息,直到第一个异常。这是否意味着我必须在控制器级别(即使用 zend-inputfilter - 我使用 ZF2/3)复制我的验证逻辑?听起来很矛盾...
先感谢您。
我将尝试一一回答您的问题,并另外给我两分钱,以及我将如何解决这些问题。
非业务逻辑相关的验证由 ValueObjects 执行
实际上 ValueObjects 代表来自您的业务领域的概念,因此这些验证实际上也是业务逻辑验证。
实体 - 在构造函数中创建用户实体时检查它?
是的,在我看来,您应该尝试在聚合中尽可能深地添加这种行为。如果你把它放在命令或命令处理程序中,你就会失去凝聚力,业务逻辑会泄漏到应用程序层。我什至会走得更远。问问自己这个问题,你的模型中是否有没有明确表达的隐藏概念。在您的情况下, anAdultUser和 an UnderagedUser(它们都可以实现 a UserInterface)实际上具有不同的行为。在这些情况下,我总是努力明确地对此进行建模。
就像电子邮件的唯一性一样。我阅读了规范模式。可以吗,如果我直接在命令处理程序中使用它?
如果您希望能够将复杂查询与逻辑运算符(尤其是读取模型)结合起来,则规范模式非常好。在你的情况下,我认为这是一种矫枉过正。在用例中添加一个简单的containsUserForEmail($emailValueObject)方法UserRepositoryInterface并从用例中调用它就可以了。
<?php
$userRepository
->containsUserForEmail($emailValueObject)
->hasOrThrow(new EmailIsAlreadyRegistered($emailValueObject));
Run Code Online (Sandbox Code Playgroud)
如何将其与 UI 验证集成?
因此,首先应该对相关字段进行客户端验证。使以正确的方式使用系统变得容易,而以错误的方式使用系统变得困难。
当然,仍然需要进行服务器端验证。我们目前使用模式验证方法,其中我们有一个中央模式注册表,我们从中获取给定有效负载的模式,然后可以根据该 JSON 模式验证 JSON 有效负载。如果失败,我们返回一个序列化的ValidationErrors对象。我们还通过Content-Type: application/json; profile=https://some.schema.url/v1/user#标头告诉客户端它如何构建有效的有效负载。
您可以在此处和此处找到有关如何在 CQRS 架构之上构建 RESTful API 的一些不错的文章。
| 归档时间: |
|
| 查看次数: |
2655 次 |
| 最近记录: |