如何在域驱动设计中共享表单和值对象之间的验证?
How to share validation between Forms and Value Objects in Domain Driven Design?
#1。验证表单上的电子邮件地址
我有一个后端表单 class,其中 emailAddress
属性 具有验证逻辑,因此我可以 return 将错误消息返回给用户。我使用类似以下内容验证所有表单输入:
$form->fillWith($request->input());
if($form->validate()){
$form->dispatch($command); // if synchronous, form takes command's messageBag
}
return response($form->getMessageBag()->toJson());
#2。在命令处理程序中验证 EmailAddress 值对象
我有一个命令处理程序,它将获取原始字符串电子邮件并创建一个值对象。如果电子邮件无效,值对象将在创建时抛出异常:
public function handle($command){
try {
$emailAddress = new ValueObjects\EmailAddress($command->emailAddress);
// create more value objects...
// do something else with the domain...
} catch (DomainException $e) {
$this->messageBag->add("errors", $e->getMessage());
} catch (\Exception $e) {
$this->messageBag->add("errors", "unexpected error");
}
return $this->messageBag;
}
在 #1 中,我想在发送命令之前尽早捕获验证。但是在#2 中,当我构建 VO 时,会重复验证逻辑。
我遇到的问题:
- 如果我需要更改电子邮件地址的验证要求,那么我必须更新这两个地方。
- 如果我在表单上使用 VO,那么在传递给命令时我将不得不再次解构它们。此外,如果我的表单位于不同的限界上下文中,那么我将从其他限界上下文中获取 VO 泄漏域(也许这是必要的?)。
所以我的问题是,我是否应该创建一些 validator 对象,我的表单验证和 VO 都可以 share/utilize?或者我如何捕获表单和值对象之间的重复验证问题?
将验证逻辑封装成可重用的class。这些class通常称为规范, 验证器或规则和是域的一部分。
有多种方法可以做到这一点,这是我使用的一种方法:
- 定义一个提供
bool IsSatisifed()
方法的接口Specification
。
- 为特定值对象实现此接口,例如
EmailWellformedSpec
.
- 通过使用规范作为前提条件在域内执行业务规则(即违反始终是编程错误)。
- 在服务层使用输入验证规范(即违反是用户错误)。
如果您想将多个规格组合成一个更大的规格,Specification Pattern 是一个很好的方法。请注意,如果您使用该模式,则需要通过构造函数传入数据,但这不是问题,因为规范 classes 通常很简单。
#1。验证表单上的电子邮件地址
我有一个后端表单 class,其中 emailAddress
属性 具有验证逻辑,因此我可以 return 将错误消息返回给用户。我使用类似以下内容验证所有表单输入:
$form->fillWith($request->input());
if($form->validate()){
$form->dispatch($command); // if synchronous, form takes command's messageBag
}
return response($form->getMessageBag()->toJson());
#2。在命令处理程序中验证 EmailAddress 值对象
我有一个命令处理程序,它将获取原始字符串电子邮件并创建一个值对象。如果电子邮件无效,值对象将在创建时抛出异常:
public function handle($command){
try {
$emailAddress = new ValueObjects\EmailAddress($command->emailAddress);
// create more value objects...
// do something else with the domain...
} catch (DomainException $e) {
$this->messageBag->add("errors", $e->getMessage());
} catch (\Exception $e) {
$this->messageBag->add("errors", "unexpected error");
}
return $this->messageBag;
}
在 #1 中,我想在发送命令之前尽早捕获验证。但是在#2 中,当我构建 VO 时,会重复验证逻辑。
我遇到的问题:
- 如果我需要更改电子邮件地址的验证要求,那么我必须更新这两个地方。
- 如果我在表单上使用 VO,那么在传递给命令时我将不得不再次解构它们。此外,如果我的表单位于不同的限界上下文中,那么我将从其他限界上下文中获取 VO 泄漏域(也许这是必要的?)。
所以我的问题是,我是否应该创建一些 validator 对象,我的表单验证和 VO 都可以 share/utilize?或者我如何捕获表单和值对象之间的重复验证问题?
将验证逻辑封装成可重用的class。这些class通常称为规范, 验证器或规则和是域的一部分。
有多种方法可以做到这一点,这是我使用的一种方法:
- 定义一个提供
bool IsSatisifed()
方法的接口Specification
。 - 为特定值对象实现此接口,例如
EmailWellformedSpec
. - 通过使用规范作为前提条件在域内执行业务规则(即违反始终是编程错误)。
- 在服务层使用输入验证规范(即违反是用户错误)。
如果您想将多个规格组合成一个更大的规格,Specification Pattern 是一个很好的方法。请注意,如果您使用该模式,则需要通过构造函数传入数据,但这不是问题,因为规范 classes 通常很简单。