如何在域驱动设计中的表单和值对象之间共享验证? [英] How to share validation between Forms and Value Objects in Domain Driven Design?

查看:189
本文介绍了如何在域驱动设计中的表单和值对象之间共享验证?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

<强>#1。验证表单上的EmailAddress



我有一个后端表单类,其中包含验证的 emailAddress 属性逻辑,以便我可以将错误消息返回给用户。我验证了所有表单输入,如:

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

if($ form-> validate()){
$ form-> dispatch($ command); //如果同步,form接受命令的messageBag
}

返回响应($ form-> getMessageBag() - > toJson());

#2。验证命令处理程序中的EmailAddress值对象



我有一个命令处理程序,它将采用原始字符串email并创建一个值对象。如果电子邮件无效,value对象将在创建时抛出异常:

  public function handle($ command){

尝试{
$ emailAddress = new ValueObjects \EmailAddress($ command-> emailAddress);

//创建更多值对象...

//对域做些其他的事情...

} catch(DomainException $ e ){
$ this-> messageBag-> add(errors,$ e-> getMessage());
} catch(\Exception $ e){
$ this-> messageBag-> add(errors,unexpected error);
}

返回$ this-> messageBag;

$ / code>

在#1中,我想在发送命令之前尽早捕获验证。但是在#2中,当我构建VO时验证逻辑会重复。



我有这些问题:


  • 如果我需要更改电子邮件的验证要求地址,那么我必须更新这两个地方。

  • 如果我在表单上使用了VO,那么在传递给命令时我将不得不再次解构它们。另外,如果我的表单处于不同的有界上下文中,那么我将会有VO从另一个有界上下文中泄漏域(可能这是必要的?)。


    所以我的问题是,我应该创建一些验证器对象,以便我的表单验证和VO可以共享/使用?或者如何捕获表单和值对象之间的重复验证问题?

    解决方案

将验证逻辑封装为可重用类。这些类通常称为规格验证器规则是域的一部分



有多种方式可以做到这一点,这里有一个我使用的方法:


  1. 定义提供 bool IsSatisifed()方法的接口 Specification

  2. 为特定的值对象实现此接口,例如 EmailWellformedSpec

  3. 使用规范作为先决条件在域中执行业务规则(即违规总是编程错误) / li>
  4. 将规范用于服务层中的输入输入验证(即违规是用户错误)。

如果您想将多个规格组合到一个更大的规格,规范模式是一个很好的做法。请注意,如果使用该模式,则需要通过构造函数传递数据,但这不是问题,因为规范类通常很简单。


#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. 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. Validate EmailAddress Value Object in the Command Handler

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:

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. But then in #2 that validation logic is repeated when I build VOs.

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. 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?).

So my question is, should I create some validator objects that both my form validation and VOs can share/utilize? 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.
  2. Implement this interface for a specific value object, e.g. EmailWellformedSpec.
  3. Enforce the business rule within the domain by using the spec as precondition (i.e. violation is always a programming error).
  4. Use the spec for input input validation in the service layer (i.e. 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.

这篇关于如何在域驱动设计中的表单和值对象之间共享验证?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆