Xero Xero - 2 months ago 12
PHP Question

Doctrine entity validation at construct

I'm trying to improve myself with doctrine, and doing best practices.
I found a good presentation of best practices : https://ocramius.github.io/doctrine-best-practices/#/50

I try to have a valid object after __construct.
(see https://ocramius.github.io/doctrine-best-practices/#/52)
But I'm using @Assert annotation for validating my object.

How can I do to validate ? Have to inject the validator service inside my object at __construct ?

My object :

class Person
{
/**
* @var int
*
* @ORM\Column(name="id", type="guid")
* @ORM\Id
* @ORM\GeneratedValue(strategy="UUID")
* @expose
*/
private $id;

/**
* @var int
*
* @ORM\Column(name="name", type="string")
* @Assert\Email()
*/
private $email;

public function __construct($email, ValidatorInterface $validator){

$this->email = $email;
$validator->validate($this); // good practice ?

}


My final goal is to unit test the input validation of this entity.

Thank you

Edit :

Basing on the answer of Yonel, I added this in the end of my constructor :

$errors = $validator->validate($this);
if(count($errors) > 0) {
$errorsString = (string) $errors;
throw new InvalidArgumentException($errorsString);
}


Is it a good practices or not ? If not, why ?
Thank you!

Answer

The presentation take best practice both from and world.

The principle you are highlighting is about the presentation layer of the application that can use a form component that can validate the user input then this data is used for instantiate the Entity.

In the example of the presentation the named constructor take as argument a form, so the validation of the email address is done by the form (validating user input).

The meaning of having an object with a valid state is intended about having an Object of type User that have both name, surname ad email valid (as example not null).

So you can have the following object:

class User
{

    private $name;

    private $surname;

    private $email;

    private function __construct(string $name, string $surname, string $email)
    {
        $this->name = $name;
        $this->surname = $surname;
        $this->email = $email;
    }

    public static function create(string $name, string $surname, string $email): User
    {
        return new static($name, $surname, $email);
    }

    public function fromFormData(FormInterface $form):User
    {
        // The form validate user input (i.e. valid email address)
        return self::create($form->get('name'), $form->get('surname'), $form->get('email'));
    }

}

Another approach could be using DTO or you can take a look at this useful bundle about validate DTOs object.

Hope this help