#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:
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?
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.
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.
Yes, you can have value objects inside other 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:
Specification
that provides a bool IsSatisifed()
method. EmailWellformedSpec
.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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With