Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

like image 994
prograhammer Avatar asked Oct 19 '15 17:10

prograhammer


People also ask

What are invariants in DDD?

In DDD, validation rules can be thought as invariants. The main responsibility of an aggregate is to enforce invariants across state changes for all the entities within that aggregate. Domain entities should always be valid entities. There are a certain number of invariants for an object that should always be true.

Can a value object reference an entity?

A value object can reference other entities. For example, in an application that generates a route that describes how to get from one point to another, that route would be a value object.

Can value objects contain other value objects?

Yes, you can have value objects inside other value objects.


1 Answers

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.

like image 89
theDmi Avatar answered Oct 01 '22 20:10

theDmi