TigerZF
🌐Español

76.4. Escritura de validadores

Zend_Validate proporciona un conjunto de validadores comúnmente necesarios, pero inevitablemente, los desarrolladores querrán escribir validadores personalizados para sus necesidades particulares. La tarea de escribir un validador personalizado se describe en esta sección.

Zend_Validate_Interface define dos métodos, isValid() y getMessages(), que pueden ser implementados por clases de usuario para crear objetos de validación personalizados. Un objeto que implemente la interfaz Zend_Validate_Interface puede añadirse a una cadena de validadores con Zend_Validate::addValidator(). Dichos objetos también pueden usarse con Zend_Filter_Input.

Como ya habrá podido inferir de la descripción anterior de Zend_Validate_Interface, las clases de validación proporcionadas con Zend Framework devuelven un valor booleano indicando si un valor se valida correctamente o no. También proporcionan información sobre por qué un valor falló la validación. La disponibilidad de las razones de los fallos de validación puede ser valiosa para una aplicación con diversos propósitos, como proporcionar estadísticas para análisis de usabilidad.

La funcionalidad básica de mensajes de fallo de validación está implementada en Zend_Validate_Abstract. Para incluir esta funcionalidad al crear una clase de validación, simplemente extienda Zend_Validate_Abstract. En la clase que extiende implementaría la lógica del método isValid() y definiría las variables de mensaje y las plantillas de mensaje que correspondan a los tipos de fallos de validación que puedan ocurrir. Si un valor falla sus pruebas de validación, entonces isValid() debería devolver FALSE. Si el valor pasa sus pruebas de validación, entonces isValid() debería devolver TRUE.

En general, el método isValid() no debería lanzar ninguna excepción, excepto cuando sea imposible determinar si el valor de entrada es válido o no. Algunos ejemplos razonables de casos para lanzar una excepción podrían ser si no se puede abrir un archivo, no se pudo contactar con un servidor LDAP, o una conexión de base de datos no está disponible, cuando tal cosa sea necesaria para determinar el éxito o fracaso de la validación.

Ejemplo 76.3. Creación de una clase de validación simple

El siguiente ejemplo demuestra cómo se podría escribir un validador personalizado muy simple. En este caso las reglas de validación son simplemente que el valor de entrada debe ser un valor de punto flotante.

class MyValid_Float extends Zend_Validate_Abstract
{
    const FLOAT = 'float';

    protected $_messageTemplates = array(
        self::FLOAT => "'%value%' is not a floating point value"
    );

    public function isValid($value)
    {
        $this->_setValue($value);

        if (!is_float($value)) {
            $this->_error(self::FLOAT);
            return false;
        }

        return true;
    }
}

La clase define una plantilla para su único mensaje de fallo de validación, que incluye el parámetro mágico incorporado, %value%. La llamada a _setValue() prepara el objeto para insertar automáticamente el valor probado en el mensaje de fallo, en caso de que el valor falle la validación. La llamada a _error() registra una razón del fallo de validación.


Ejemplo 76.4. Escritura de una clase de validación con condiciones dependientes

El siguiente ejemplo demuestra un conjunto de reglas de validación más complejo, donde se requiere que el valor de entrada sea numérico y esté dentro del rango de valores límite mínimo y máximo. Un valor de entrada fallaría la validación por exactamente una de las siguientes razones:

  • El valor de entrada no es numérico.

  • El valor de entrada es menor que el valor mínimo permitido.

  • El valor de entrada es mayor que el valor máximo permitido.

Estas razones de fallo de validación se traducen entonces a definiciones en la clase:

class MyValid_NumericBetween extends Zend_Validate_Abstract
{
    const MSG_NUMERIC = 'msgNumeric';
    const MSG_MINIMUM = 'msgMinimum';
    const MSG_MAXIMUM = 'msgMaximum';

    public $minimum = 0;
    public $maximum = 100;

    protected $_messageVariables = array(
        'min' => 'minimum',
        'max' => 'maximum'
    );

    protected $_messageTemplates = array(
        self::MSG_NUMERIC => "'%value%' is not numeric",
        self::MSG_MINIMUM => "'%value%' must be at least '%min%'",
        self::MSG_MAXIMUM => "'%value%' must be no more than '%max%'"
    );

    public function isValid($value)
    {
        $this->_setValue($value);

        if (!is_numeric($value)) {
            $this->_error(self::MSG_NUMERIC);
            return false;
        }

        if ($value < $this->minimum) {
            $this->_error(self::MSG_MINIMUM);
            return false;
        }

        if ($value > $this->maximum) {
            $this->_error(self::MSG_MAXIMUM);
            return false;
        }

        return true;
    }
}

Las propiedades públicas $minimum y $maximum se han establecido para proporcionar los límites mínimo y máximo, respectivamente, para que un valor se valide correctamente. La clase también define dos variables de mensaje que corresponden a las propiedades públicas y permiten que min y max se usen en las plantillas de mensaje como parámetros mágicos, tal como con value.

Note que si alguna de las comprobaciones de validación en isValid() falla, se prepara un mensaje de fallo apropiado, y el método devuelve inmediatamente FALSE. Estas reglas de validación son, por lo tanto, secuencialmente dependientes. Es decir, si una prueba falla, no hay necesidad de probar ninguna regla de validación posterior. Sin embargo, esto no tiene por qué ser así. El siguiente ejemplo ilustra cómo escribir una clase con reglas de validación independientes, donde el objeto de validación puede devolver múltiples razones por las que un intento de validación en particular falló.


Ejemplo 76.5. Validación con condiciones independientes, múltiples razones de fallo

Considere escribir una clase de validación para la aplicación de la fortaleza de contraseñas - cuando se requiere que un usuario elija una contraseña que cumpla ciertos criterios para ayudar a proteger las cuentas de usuario. Supongamos que los criterios de seguridad de la contraseña exigen que la contraseña:

  • tenga al menos 8 caracteres de longitud,

  • contenga al menos una letra mayúscula,

  • contenga al menos una letra minúscula,

  • y contenga al menos un carácter numérico.

La siguiente clase implementa estos criterios de validación:

class MyValid_PasswordStrength extends Zend_Validate_Abstract
{
    const LENGTH = 'length';
    const UPPER  = 'upper';
    const LOWER  = 'lower';
    const DIGIT  = 'digit';

    protected $_messageTemplates = array(
        self::LENGTH => "'%value%' must be at least 8 characters in length",
        self::UPPER  => "'%value%' must contain at least one uppercase letter",
        self::LOWER  => "'%value%' must contain at least one lowercase letter",
        self::DIGIT  => "'%value%' must contain at least one digit character"
    );

    public function isValid($value)
    {
        $this->_setValue($value);

        $isValid = true;

        if (strlen($value) < 8) {
            $this->_error(self::LENGTH);
            $isValid = false;
        }

        if (!preg_match('/[A-Z]/', $value)) {
            $this->_error(self::UPPER);
            $isValid = false;
        }

        if (!preg_match('/[a-z]/', $value)) {
            $this->_error(self::LOWER);
            $isValid = false;
        }

        if (!preg_match('/\d/', $value)) {
            $this->_error(self::DIGIT);
            $isValid = false;
        }

        return $isValid;
    }
}

Note que las cuatro pruebas de criterios en isValid() no devuelven inmediatamente FALSE. Esto permite que la clase de validación proporcione todas las razones por las que la contraseña de entrada no cumplió los requisitos de validación. Si, por ejemplo, un usuario introdujera la cadena "#$%" como contraseña, isValid() haría que los cuatro mensajes de fallo de validación fueran devueltos por una llamada posterior a getMessages().