Symfony2: Constraints

En este artículo vamos a cómo son los Constraints. En la documentación de Symfony hay una referencia a todas ellos, aquí vamos a ver las clases implicadas.

Cuando en una Entity, modelo, en un formulario o donde sea usamos Constraints como NotBlank, NotNull, Email, etc. Realmente, ¿qué está pasando? Lo que estamos indicando es que estamos asociando que un determinado campo o clase (según donde lo apliquemos) debe cumplir con ese Constraint. Y ¿dónde está el código que se ejecuta para estas comprobaciones? Dentro del componente Validator, están definidas estos Constraints.

Vamos a ver NotNull. Todos las Constraints están divididos en dos clases, por una parte tenemos el propio Constraint:

Esta clase extiende de Constraint y aquí se definen las propiedades y configuración, en este caso el mensaje que aparecerá cuando no se cumpla. Destacar también la anotación Annotation que permite luego poder usar la clase en una anotación.

Por otra parte tenemos el Validator:

Esta clase es la que se va a encargar de tener la lógica de validación en el método validate, el cual recibe el valor a validar y la Constraint de configuración. A través del atributo context añadimos las violaciones en el caso que se produjeran.

¿Qué cosas podemos configurar de la clase Constraint?

Lo mejor es ver una ya hecha, vamos a usar de ejemplo el Constraint UniqueEntity:

Lo primero que salta a la vista, es que podemos añadirle atributos públicos. Estos atributos contienen información sobre la configuración que usaremos en el Validator y los podemos sobrescribir cuando instanciamos el Constraint:

Otra cosa importante que podemos configurar es el target con el método getTargets, la Constraint puede afectar a una propiedad, un método o una clase entera, en el caso de la propiedad, a la hora de validar sólo tendremos acceso al valor que contiene. Si indicamos, como en el caso de UniqueEntity que el Target es la clase, tendremos acceso a una instancia de esa clase en el Validator, por lo que podemos acceder a los métodos o atributos públicos que tenga:

Por otra parte podemos indicar qué campos son los requeridos:

Y cuál es el campo por defecto si sólo nos envían un parámetro de configuración:

Por lo que si añadimos el Constraint así:

Es como si lo indicáramos así:

También podemos indicar el groups como en todas las constraints y finalmente tenemos el método validatedBy que indica cuál va a ser el Validator asociado. Por defecto es una clase que se llama igual que el Constraint + Validator:

Cuando creamos un Validator al que le debemos inyectar algunas dependencias, tendremos que declarar el Validator como servicio y tendremos que añadirle el tag validator.constraint_validator y un alias que será el mismo nombre que el método validatedBy deberá devolver, que es justo que lo hace UniqueEntity.

En la documentación oficial podéis encontrar cómo crear un Custom Validator.