Skip to content

Instantly share code, notes, and snippets.

@gquemener
Last active July 29, 2020 17:51
Show Gist options
  • Save gquemener/09b2bc303e63dfc3123f7d540e9891a0 to your computer and use it in GitHub Desktop.
Save gquemener/09b2bc303e63dfc3123f7d540e9891a0 to your computer and use it in GitHub Desktop.
Self validating command (using symfony validator)
<?php
abstract class Command
{
// Self-validating command
public static function loadValidatorMetadata(ClassMetadata $metadata): void
{
$metadata->addConstraint(
new Callback(function(Command $command, ExecutionContextInterface $context) {
$reflClass = new \ReflectionClass($command);
foreach ($reflClass->getProperties(\ReflectionProperty::IS_PUBLIC) as $reflProp) {
if (
!$reflClass->hasMethod($reflProp->getName())
|| !$reflClass->getMethod($reflProp->getName())->isPublic()
) {
continue;
}
// Domain will detect invalid data and we will expose those errors to the world
try {
$command->{$reflProp->getName()}();
} catch (\InvalidArgumentException $e) {
$context->buildViolation($e->getMessage())
->atPath($reflProp->getName())
->setInvalidValue($command->{$reflProp->getName()})
->addViolation()
;
}
}
})
);
}
}
<?php
final class DoSomethingOnFoo extends Command
{
private string $id;
private string $bar;
public function __construct(string $id, string $bar)
{
$this->id = $id;
$this->bar = $bar;
}
public function id(): FooId
{
return FooId::fromString($this->id);
}
public function bar(): Bar
{
return Bar::fromString($this->bar);
}
}
<?php
$command = new DoSomethingOnFoo('123ABC', 'Lorem Ipsum');
$validator = new class implements \Symfony\Component\Validator\Validator\ValidatorInterface
{
//...
};
$errors = $validator->validate($command);
if (count($errors) > 0) {
// convert errors to whatever format that suits your need, (eg: json, terminal output, ....)
}
$commandBus->dispatch($command);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment