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().