我最近开始玩 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;
}
}
非业务逻辑相关的验证由 ValueObjects 执行。没关系。我在放置业务逻辑规则验证时遇到问题。
假设我们需要让 18 岁以上的用户拥有自己的电子邮件地址怎么办?我们必须检查今天的年龄,如果不正常则抛出异常。
我应该把它放在哪里?
- 实体 - 在构造函数中创建用户实体时检查它?
- 命令 - 在执行插入/更新/任何命令时检查它?我在我的项目中使用战术家,所以它应该是一份工作
- 命令
- 命令处理程序
在哪里放置负责检查存储库数据的验证器?
就像电子邮件的唯一性。我阅读了规范模式。如果我直接在命令处理程序中使用它可以吗?
最后但并非最不重要。
如何将其与 UI 验证集成?
我上面描述的所有内容都是关于域级别的验证。但是让我们考虑从 REST 服务器处理程序执行命令。我的 REST API 客户端希望我在输入数据错误的情况下返回有关问题的完整信息。我想返回带有错误描述的字段列表。实际上,我可以将所有命令准备都包装在 try 块中并侦听 Validation 类型的异常,但主要问题是它会为我提供有关单个错误的信息,直到第一个异常。这是否意味着我必须在控制器级别复制我的验证逻辑(即使用 zend-inputfilter - 我正在使用 ZF2/3)?听起来很不协调...
先感谢您。