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

自闭症网瘾萝莉.ら 提交于 2019-12-17 20:12:39

问题


#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?


回答1:


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.



来源:https://stackoverflow.com/questions/33220394/how-to-share-validation-between-forms-and-value-objects-in-domain-driven-design

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!