Symfony. Validate an object based on its previous version

How to validate an object using the Validator component of Symfony and taking into account its previous version

Gerardo Fernández
Sep 4, 2019 · 5 min read
Photo by Icons8 team on Unsplash

Today I bring you one of those recipes for Symfony that is always good to know if at any time we find the opportunity to apply it. Basically, what I intend in this article is to teach you to validate an object that we are persisting through Doctrine based on the value it had previously.
In other words, suppose we have the entity:

and a MyEntityFormType class that represents the form with which we create and modify objects of this class:

What we are looking for is to add a validation to the title field so that, depending on the value it had previously, the new value is valid or not. For example, we are going to work on the following validation: the length of the value entered for title must always be greater than that of the previous value. That is, if before title stored the string “Title”, a new valid value would be “Another Title” but not “Title”.

This recipe will also allow us to familiarize ourselves with the Validator component as well as with the Doctrine UnitOfWork concept of which I talked to you before on this article:

So I encourage you to reach the end because I think it is very interesting.

So that said, let’s go there.

Defining a “Constraint class”

Since Symfony and the Validator component allow us to solve the case we have raised with one of the Constraints that we have by default, what we will have to do is create our own.

So the first thing we will do is create a class called TitleLength inside the src src/Validator/Constraints folder:

From this class I would like to highlight 3 things:

  • We need to add the Annotation @Annotation if we want to use this Constraint through annotations in the class to be validated.
  • The $message property can have what you want and will be the error message that the form will contain in case the new title does not pass the validation.
  • And finally and most importantly, we need to declare this Constraint as a CLASS_CONSTRAINT since we will subsequently need to receive in the validator associated with this Constraint the object of the MyEntity class and not the title property.

Defining a “Validator” class

That said, the next thing we will do is write the validator of this Constraint. To do this, we will create a class called TitleLengthValidator within it where we create the constraint.

Symfony is able to automatically associate the validator associated with each Constraint. For this, the Validator class will be named as “constraint name + Validator”

To perform the validation, the first thing we will need is the EntityManager, so we inject it using the Symfony autowire.

Once this is done, we will write the validate method which receives two arguments:

  • The value or object to validate
  • The Constraint that is being validated

Since what we want is to check the length of the new title with that of the previous one, we will need to recover that previous value. This is where knowing the concept of Doctrine UnitOfWork becomes important, because thanks to these “work units” we can retrieve the object as it is in the database.

¡Wow! Please, clarify UnitOfWork concept

Imagine we want to edit objects of the MyEntity class. What we will have done in our controller will have been to retrieve it by id through the associated repository, create a form of the MyEntityFormType class by passing said object and associate that form to the Request through the handleRequest method:

Thus, when the user submits the form, the handleRequest method will map the values sent to the $obj object so it will now contain the values sent and not those found in the database.

That is why we need to use a Doctrine UnitOfWork to retrieve the previous values (those found in the database), since if we tried using $myEntityRepo->findOneById(1) what Doctrine would do would be to return a “cached” version “with the new values, it will consider that this reference has it already loaded in memory and it is not necessary to go to search for it in the database.

Let’s continue with the TitleLengthValidator class

Now I think it is clearer why we need to declare the constraint as CLASS_CONSTRAINT, because what we need is to receive the object in the validator in order to be able to recover it through the UnitOfWork.

Explained this, the rest of the code of the TitleLengthValidator class is quite simple: we will verify that the length of the new value exceeds that of the old value and if not, we will create an error.

Associate the TitleLength constraint with the entity

And the last step will be to associate our constraint with the entity. I will use annotations for convenience, for which we will go to src/Entity/MyEntity.php and add what you see below:

In this way, whenever we are going to create or modify an object of the MyEntity class, our TitleLength constraint will be checked.

¿Quieres recibir más artículos como este?

Suscríbete a nuestra newsletter:

Gerardo Fernández

Written by

Entre paseo y paseo con Simba desarrollo en Symfony y React

More From Medium

More from Gerardo Fernández

More from Gerardo Fernández

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade