Blog


Crea tu propio validador en Symfony2

CREA TU PROPIO VALIDADOR EN SYMFONY2

01 / 07 / 2013 Symfony

En el desarrollo de aplicaciones web, es muy común el uso de formularios y por extensión, la validación de sus campos para controlar qué información se almacena en la base de datos. Symfony2 cuenta con el componente Validator que facilita esta tarea y que ya implementa una serie de validadores como NotBlank, NotNull, Email, EqualTo, LessThan, Date, Collection o Isbn, entre muchos otros.

Supongamos que tenemos un objeto Producto con un atributo nombre, vamos a ver cómo validar, por ejemplo, que su campo nombre no sea nulo. Para ello, necesitaremos configurar una serie de reglas, llamadas constraints, que nuestro objeto Producto debe cumplir con el fin de ser válido. Estas reglas se pueden especificar en diferentes formatos, YAML, XML, mediante anotaciones o con PHP. En nuestro ejemplo, usaremos anotaciones:


use Symfony\Component\Validator\Constraints as Assert;

class Producto {    
     /**     
       * @AssertNotBlank()     
       */    
     protected $nombre;

     /* ... */
}

Normalmente, en nuestros desarrollos se presenta la necesidad de crear validadores específicos para necesidades del proyecto que no están cubiertas por los validadores incluidos en el componente Validator de Symfony2. En este artículo vamos a intentar explicar de la manera más sencilla posible, cómo hacerlo. Como ejemplo, crearemos un validador alfanumérico para que en una cadena de texto solo se incluyan números y letras.

Para crear un validador personalizado en Symfony2, crearemos una clase Constraint que extendienda de la clase base Constraint. Para que este nuevo validador esté disponible para su uso, debemos incluir la anotación @Annotation, de la siguiente manera:


namespace Vabadus\VabadusBundle\Validator\Constraints;

use Symfony\Component\Validator\Constraint;

/**
 * @Annotation
 */
class ContieneAlfanumerico extends Constraint
{
     public $message = 'La cadena "%string%" contiene un caracter ilegal: solo puede contener letras y números.';
}

Con esto tenemos creada la clase del nuevo validador, la lógica de la validación irá incluida en otra clase que extiende ConstraintValidator y cuyo nombre llevará la terminación -Validator, en nuestro caso, ContieneAlfanumericoValidator. Esto es así, ya que cuando se crea un validador personalizado, con el nombre MiValidador, y se realiza una validación, Symfony2 busca automáticamente, mediante el método validatedBy(), otra clase cuyo nombre sea MiValidadorValidator.


public function validatedBy()
{
     return get_class($this).'Validator';
}

Siguiendo con el ejemplo, vamos a ver cómo queda nuestra clase con la lógica de validación, que únicamente contendrá el método validate. Éste, no retorna ningún valor, sino que se suma a otros posibles errores que se hayan producido al validar, mediante la llamada al método addViolation, pasando como primer parámetro el mensaje de error que se utilizará para este caso:


namespace Vabadus\VabadusBundle\Validator\Constraints;

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;

class ContieneAlfanumericoValidator extends ConstraintValidator
{
     public function validate($value, Constraint $constraint)
     {
          if (!preg_match('/^[a-zA-Za0-9]+$/', $value, $matches)) {
               $this->context->addViolation($constraint->message, array('%string%' => $value));
          }
      }
}

Llegados a este punto, ya tenemos creado completamente nuestro validador y vamos a ver cómo podemos usarlo en nuestro desarrollo. El uso es similar a como lo hacemos con los validadores que nos proporciona el componente Validator de Symfony2 y que en nuestro caso, usando anotaciones, quedaría de la siguiente manera:


use Symfony\Component\Validator\Constraints as Assert;
use Vabadus\VabadusBundle\Validator\Constraints as VabadusAssert;

class ProductoEntity
{
    /* ... */

    /**
     * @Assert\NotBlank
     * @Vabadus\Assert\ContieneAlfanumerico
     */
    protected $nombre;

    /* ... */
}

Hasta aquí hemos visto el caso más sencillo para crear nuestros propios validadores. Pero puede darse el caso de que nuestro validador tenga alguna dependencia como puede ser, por ejemplo, una conexión a base de datos. En ese caso, tendremos que configurar nuestro validador como un servicio en el contenedor de inyección de dependencias, incluyendo el tag validator.constraint_validator junto con un alias, de la siguiente manera:


services:
    validator.unico.nombre_validador:
        class: Vabadus\VabadusBundle\Validator\ClassName
        tags:
            - { name: validator.constraint_validator, alias: nombre_alias }

Antes decíamos que Symfony2 busca automáticamente una clase con la terminación Validator, pero en este caso en el que definimos el validador como un servicio, es necesario sobreescribir el método validatedBy() para que devuelva el alias usado en la definición del servicio.


public function validatedBy()
{
     return 'alias_name';
}



ARTÍCULOS RELACIONADOS