Validación datos dependientes en entidad Symfony2

Al aprender php o cualquier otro lenguaje de programación, llegamos a la situación de tener que validar datos, cuando unos campos están completados o no. Es una tarea bastante habitual cuando desarrollamos proyectos web.

Symfony2 nos permiten de un modo bastante sencillo realizar estas validaciones (validation) dependientes entre campos de la misma entidad (entity)

En este post voy a poner un ejemplo para una validación que se realiza desde un único archivo, teniendo otro más de apoyo para los mensajes cuando no se cumplan los criterios que definamos.

Vamos a suponer una entidad Producto, donde tenemos un campo buleano talla, y otro campo valorTalla, donde valorTalla es obligatorio si se indica que talla es «si».

Validación datos

Aquí tenemos la entidad Producto.php

<?php

namespace AppBundle\Entity;

//...
// Validación a medida
use AppBundle\Validator\Constraints as EagAssert;


/**
 * Producto
 *
 * @ORM\Table()
 * @EagAssert\Bodas
 */
class Bodas {

    //..

    /**
     * @var boolean
     *
     * @ORM\Column(name="talla", type="boolean", options={"default" = 0}, nullable=true
     */
    private $talla;

    /**
     * @var string
     *
     * @ORM\Column(name="valorTalla", type="text", nullable=true)
     */
    private $valorTalla;


    //..

}

En la línea 7 es donde incluimos el validador:

use AppBundle\Validator\Constraints as EagAssert;

EagAssert es el nombre que yo le he dado, puedes utilizar el que mejor te parezca.

En la línea 14, definimos que clase es la que vamos a utilizar:

* @EagAssert\Producto

En la carpeta Validator\Contraints vamos a tener 2 archivos, estos deben comenzar con el nombre que hemos dado en la línea anterior, la 14, uno para los mensajes de validación, donde creamos una clase Constraint que extiende a Constraint, Producto.php:

<?php

namespace AppBundle\Validator\Constraints;

use Symfony\Component\Validator\Constraint;

/**
 * Class Producto
 * @author Juanjo García
 *
 * @Annotation
 */
class Producto extends Constraint {
    
    public $mensajeTalla = 'Si has indicado que el producto tiene talla, debes indicar una';
    

    public function getTargets() {
        return self::CLASS_CONSTRAINT;
    }

}

Y otro archivo para realizar la validación propiamente dicha, ProductoValidator.php

<?php

namespace AppBundle\Validator\Constraints;

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

/**
 * Class ProductoValidator
 * 
 * @author Juanjo García
 */
class ProductoValidator extends ConstraintValidator {

    /**
     * @var \Symfony\Component\Validator\Context\ExecutionContextInterface
     */
    protected $context;

    /**
     * Checks if the passed value is valid.
     *
     * @param mixed $protocol The value that should be validated
     * @param Constraint $constraint The constraint for the validation
     *
     * @api
     */
    public function validate($protocol, Constraint $constraint) {
        /*
         * Comprobamos que se ha marcado que el producto tiene talla
         * y por lo tanto el campo valorTalla tiene que tener un valor
         */
        if ($protocol->getTalla() && is_null($protocol->getValorTalla()) {
            // If you're using the new 2.5 validation API (you probably are!)
            $this->context->buildViolation($constraint->mensajeTalla)
                    ->atPath('valorTalla') //aquí le digo el campo donde tiene que mostrar el error
                    ->addViolation();
        }

    }

}

Con esto ya tenemos un ejemplo básico, que nos sirve de base para poder realizar muchas más validaciones en una misma entidad, haciendo uso de estos 2 mismos archivos.

Referencias

Enlace a documentación oficial de Symfony