Symfony. Validar un objeto en función de su versión previa

Gerardo Fernández
Jul 5 · 5 min read

Hoy os traigo una de esas recetas que siempre está bien conocer por si en algún momento nos encontramos con la oportunidad de aplicarla. Básicamente lo que pretendo en este artículo es enseñaros a validar un objeto que estamos persistiendo por medio de Doctrine en función del valor que tenía previamente.

Dicho de otro modo, supongamos que tenemos la entidad:

y una clase MyEntityFormType que representa el formulario con el cual creamos y modificamos objetos de esta clase:

Lo que buscamos es añadir una validación al campo title de modo que, en función del valor que tuviese previamente, el nuevo valor sea o no válido. Por ejemplo vamos a trabajar sobre la siguiente validación: la longitud del valor introducido para title tiene que ser siempre superior a la que tenía el valor anterior. Es decir, si antes title almacenaba el string Título , un nuevo valor válido sería Otro Título pero no así Title .

Esta receta además nos permitirá familiarizarnos con el componente Validator así como con el concepto de UnitOfWork de Doctrine del cual ya os hablé anteriormente por lo que os animo a llegar hasta el final porque creo que es muy interesante.

Así que dicho esto, vamos allá.

Definiendo una constraint

Así que lo primero que haremos será crear una clase llamada TitleLength dentro de la carpeta src/Validator/Constraints :

De esta clase me gustaría resaltar 3 cosas:

  • Necesitamos añadir la Annotation @Annotation si queremos emplear esta Constraint mediante anotaciones en la clase a validar.
  • La propiedad $message puede tener lo que queráis y será el mensaje de error que contendrá el formulario en el caso de que el nuevo title no supere la validación.
  • Y finalmente y la más importante, necesitamos declarar esta Constraint como una CLASS_CONSTRAINT ya que posteriormente necesitaremos recibir en el validador asociado a esta Constraint el objeto de la clase MyEntity y no la propiedad title .

Definiendo un validador

Symfony es capaz de asociar automáticamente el validador asociado a cada Constraint . Para ello, la clase Validator la nombraremos como “nombre de la constraint + Validator”

Para realizar la validación, lo primero que necesitaremos es el EntityManager , por lo que lo inyectamos mediante el autowire de Symfony.

Hecho esto, escribiremos el método validate el cual recibe dos argumentos:

  • El valor u objeto a validar
  • La Constraint que se está validando

Puesto que lo que queremos es comprobar la longitud del nuevo título con la del anterior, necesitaremos recuperar dicho valor anterior. Es aquí donde conocer el concepto de UnitOfWork de Doctrine cobra importancia, ya que gracias a estas “unidades de trabajo” podremos recuperar el objeto tal y como se encuentra en base de datos.

A ver, a ver, explica mejor eso de la UnitOfWork

De este modo, cuando el usuario envía el formulario, el método handleRequest mappeará los valores enviados al objeto $obj por lo que ahora contendrá los valores enviados y no los que se encuentran en base de datos. Es por ello que necesitamos emplear una UnitOfWork de Doctrine para recuperar los valores anteriores (los que se encuentran en base de datos), ya que si lo intentásemos empleando $myEntityRepo->findOneById(1) lo que haría Doctrine sería devolvernos una versión “cacheada” con los nuevos valores, pues considerará que dicha referencia la tiene ya cargada en memoria y no es necesario irla a buscar a base de datos.

Sigamos con la clase TitleLengthValidator

Explicado esto, el resto del código de la clase TitleLengthValidator es bastante sencillo: comprobaremos que la longitud del nuevo valor supera la del antiguo y si no es así crearemos un error.

Asociar la constraint TitleLength a la entidad

De este modo, siempre que vamos a crear o modificar un objeto de la clase MyEntity nuestra constraint TitleLength será comprobada.

Gerardo Fernández

Written by

Mejor amigo de Simba y desarrollador 100% fullstack