简体   繁体   English

如何在域驱动设计中的表单和值对象之间共享验证?

[英]How to share validation between Forms and Value Objects in Domain Driven Design?

#1. #1 Validate EmailAddress on the Form 验证表单上的电子邮件地址

I have a backend form class with an emailAddress property that has validation logic so that I can return an error message back to the user. 我有一个带有emailAddress属性的后端表单类,该类具有验证逻辑,以便可以将错误消息返回给用户。 I validate all form inputs with something like: 我用以下方法验证所有表单输入:

$form->fillWith($request->input());

if($form->validate()){
    $form->dispatch($command); // if synchronous, form takes command's messageBag
}

return response($form->getMessageBag()->toJson());

#2. #2。 Validate EmailAddress Value Object in the Command Handler 在命令处理程序中验证EmailAddress值对象

I have a command handler that will take the primitive string email and create a value object. 我有一个命令处理程序,它将使用原始字符串电子邮件并创建一个值对象。 The value object will throw an exception on creation if the email is invalid: 如果电子邮件无效,则value对象将在创建时引发异常:

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;
}

In #1, I want to capture validation early before I dispatch a command. 在#1中,我想在调度命令之前尽早捕获验证。 But then in #2 that validation logic is repeated when I build VOs. 但是然后在#2中,当我构建VO时,将重复验证逻辑。

Issues I have: 我遇到的问题:

  • If I need to change validation requirements on email addresses, then I have to update both places. 如果需要更改电子邮件地址的验证要求,则必须更新两个地方。
  • If I use VOs on my form then I will have to deconstruct them again when passing to the command. 如果我在表单上使用VO,那么在传递给命令时,我将不得不再次对其进行解构。 Also, if my form is in a different Bounded Context then I will have VOs leaking domain from the other Bounded Context (maybe this is necessary?). 另外,如果我的表单处于不同的绑定上下文中,那么我将从其他绑定上下文中获取VO泄漏域(也许这是必要的吗?)。

So my question is, should I create some validator objects that both my form validation and VOs can share/utilize? 所以我的问题是,我是否应该创建一些验证器对象,以便表单验证和VO都可以共享/利用? Or how do I capture repeated validation concerns between forms and value objects? 还是如何捕获表单和值对象之间的重复验证问题?

Encapsulate the validation logic into a reusable class. 将验证逻辑封装到可重用的类中。 These classes are usually called specifications , validators or rules and are part of the domain . 这些类通常称为规范验证器规则,并且是域的一部分

There are multiple ways of doing this, here is an approach that I use: 有多种方法可以执行此操作,这是我使用的一种方法:

  1. Define an interface Specification that provides a bool IsSatisifed() method. 定义提供bool IsSatisifed()方法的接口Specification
  2. Implement this interface for a specific value object, eg EmailWellformedSpec . 为特定的值对象(例如EmailWellformedSpec实现此接口。
  3. Enforce the business rule within the domain by using the spec as precondition (ie violation is always a programming error). 通过使用规范作为前提条件来在域内强制执行业务规则(即,违反总是编程错误)。
  4. Use the spec for input input validation in the service layer (ie violation is a user error). 将规范用于服务层中的输入输入验证(即,违反是用户错误)。

If you want to combine multiple specs to a larger one, the Specification Pattern is a good approach. 如果要将多个规范合并为一个较大的规范 ,则“ 规范模式”是一种不错的方法。 Note that you need to pass in the data through the constructor if you use that pattern, but this is not a problem because the specification classes are usually simple. 请注意,如果使用该模式,则需要通过构造函数传递数据,但这不是问题,因为规范类通常很简单。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM