Cómo programar con Yii2: Validaciones especializadas
Spanish (Español) translation by Elías Nicolás (you can also view the original English article)



Si usted está preguntando, "¿Qué es Yii?" Echa
un vistazo a mi tutorial anterior: Introducción a Yii Framework, que
revisa los beneficios de Yii e incluye una visión general de lo que es
nuevo en Yii 2.0, publicado en octubre de 2014.
En esta serie programación con Yii2, estoy guiando a los lectores en el uso de la nueva actualización de Yii2 Framework para PHP. Este tutorial es nuestra segunda parte, mirando los validadores de Yii2. Los validadores simplifican el código necesario para validar la entrada, es decir, verificar la conformidad o no conformidad de la entrada de datos, típicamente de los usuarios a través de formularios web. Específicamente, vamos a explorar algunas de las validaciones de especialidad incorporadas que son comunes para el desarrollo web.
Aquí hay una lista de los validadores incorporados de Yii y enlaces a la documentación que vamos a explorar:
- CaptchaValidator: Valida un campo de verificación de formulario CAPTCHA.
- CompareValidator: compara dos valores de la forma o una constante, p. X debe ser menor que 99.
- EmailValidator: asegura que un valor es una dirección de correo electrónico válida.
- ExistValidator: Asegura que existe un valor en otra tabla.
- FileValidator: Asegura la existencia de un archivo subido.
- ImageValidator: Valida las propiedades de imagen e imagen.
- RangeValidator: Asegura que un valor esté dentro de una lista de valores.
- RegularExpressionValidator: Realiza la validación en función de una condición definida por una expresión regular.
- UniqueValidator: asegura que el valor es único dentro de una tabla, como una dirección de correo electrónico.
- UrlValidator: asegura que el valor esté en formato de URL, p. http://example.com.
Voy a guiarte a través de ejemplos de cada una de estas validaciones usando la base de código Hello de aplicaciones de tutoriales pasados y un par de nuestra serie Contruyendo su startup que también usa Yii2. Utilice los enlaces de GitHub en esta página para descargar el código.
Sólo un recordatorio, participo en los comentarios de abajo. Estoy especialmente interesado si tienes ideas adicionales o quieres sugerir temas para futuros tutoriales. También puedes contactarme @reifman en Twitter o enviarme un correo electrónico a Lookahead Consulting.
¿Qué es un Validator?
Si eres un desarrollador web, probablemente sabes que no se puede confiar en la entrada del usuario. Por ejemplo, los usuarios pueden utilizar técnicas de inyección de SQL para intentar ejecutar consultas que cambien o expongan contraseñas. Alguien una vez aprovechó la inyección de SQL contra mi instalación de PHPList de código abierto y logré descubrir una de mis contraseñas (PHPList las guardó en texto sin formato). Más comúnmente, sólo desea asegurarse de que los usuarios de datos proporcionan se ajusta a los tipos, formas y rangos de su aplicación.
Construir validadores en PHP a mano toma tiempo. El marco de Yii proporciona una tonelada de características de la validación de la línea de fondo así que no hay necesidad de construirlas de rasguño. Pero, si necesita algunas extensiones personalizadas, también es sencillo.
Las
validaciones son otra razón por la que pienso que siempre tiene sentido
construir aplicaciones en un framework web como Yii en lugar de PHP.
En episodios anteriores, también hemos hablado mucho sobre el generador de código de Yii, Gii. Uno de los beneficios de Gii es que escribirá las reglas de validación apropiadas para sus modelos basándose en las definiciones de tipo SQL en el esquema. Este es un gran ahorro de tiempo.
Es posible que desee volver a nuestro último episodio para leer más sobre validaciones de básicas de tipos en Yii2.
Ahora, comencemos a ver el siguiente conjunto de validadores incorporados de Yii2.
El siguiente conjunto de validadores
El Validador de Captcha
Comencemos con CaptchaValidator que comprueba que hay una respuesta adecuada a un campo de verificación CAPTCHA. CAPTCHAs ayudan a asegurar que un humano está llenando el formulario, con suerte alejando a scripts automatizados de enviarlo.
He aquí un ejemplo del Yii Captcha en acción:



En nuestro Hello, he simplificado nuestro formulario de ejemplo para incluir los campos de Pensamiento y Captcha por ahora. He aquí un vistazo a las definiciones de reglas del código de modelo:
1 |
class Sample extends \yii\db\ActiveRecord |
2 |
{
|
3 |
public $captcha; |
4 |
|
5 |
/**
|
6 |
* @inheritdoc
|
7 |
*/
|
8 |
public function rules() |
9 |
{
|
10 |
return [ |
11 |
[['thought'], 'string', 'max' => 255], |
12 |
[['thought'], 'trim'], |
13 |
[['thought'], 'required'], |
14 |
[['captcha'], 'captcha'], |
15 |
];
|
16 |
}
|
El captcha no es parte de nuestro esquema de base de datos, solo se usa para verificar el formulario. Por lo tanto, he añadido un atributo al modelo para ello, p. public $captcha;.
Aquí está el código de vista para el formulario. Tenemos que incluir la biblioteca Captcha en la parte superior.
1 |
<?php
|
2 |
|
3 |
use yii\helpers\Html; |
4 |
use yii\widgets\ActiveForm; |
5 |
use yii\captcha\Captcha; |
6 |
|
7 |
/* @var $this yii\web\View */
|
8 |
/* @var $model app\models\Sample */
|
9 |
/* @var $form yii\widgets\ActiveForm */
|
10 |
?>
|
11 |
|
12 |
<div class="sample-form"> |
13 |
|
14 |
<?php $form = ActiveForm::begin(); ?> |
15 |
<?= $form->errorSummary($model); ?> |
16 |
|
17 |
<?= $form->field($model, 'thought')->textInput(['maxlength' => 255]) ?> |
18 |
|
19 |
<?= $form->field($model, 'captcha')->widget(\yii\captcha\Captcha::classname(), [ |
20 |
// configure additional widget properties here
|
21 |
]) ?> |
22 |
|
23 |
<div class="form-group"> |
24 |
<?= Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?> |
25 |
</div>
|
26 |
|
27 |
<?php ActiveForm::end(); ?> |
28 |
|
29 |
</div>
|
Asi es como se ve la validación de Captcha en acción:



Si hace clic en la Captcha, Yii generará una nueva imagen.
El validador de comparación
Ahora, vamos a pasar a la CompareValidator. Este validador compara dos valores de la forma o un único valor de formulario a una constante, como x debe ser menor que 99.
Para este ejemplo, quiero asegurarme de que la entrada de usuario para el rango sea mayor que cero pero menor o igual a 100.
En primer lugar, añadiré el campo de entrada a nuestro formulario para el atributo rank:
1 |
<?php $form = ActiveForm::begin(); ?> |
2 |
<?= $form->errorSummary($model); ?> |
3 |
|
4 |
<?= $form->field($model, 'thought')->textInput(['maxlength' => 255]) ?> |
5 |
|
6 |
<?= $form->field($model, 'rank')->textInput() ?> |
7 |
|
8 |
<?= $form->field($model, 'captcha')->widget(\yii\captcha\Captcha::classname(), [ |
9 |
// configure additional widget properties here
|
10 |
]) ?> |
Luego agregaré dos reglas de validación de comparación a nuestro modelo:
1 |
public function rules() |
2 |
{
|
3 |
return [ |
4 |
[['thought'], 'string', 'max' => 255], |
5 |
[['thought'], 'trim'], |
6 |
[['thought'], 'required'], |
7 |
[['captcha'], 'captcha'], |
8 |
[['rank'], 'integer'], |
9 |
['rank', 'compare', 'compareValue' => 0, 'operator' => '>'], |
10 |
['rank', 'compare', 'compareValue' => 100, 'operator' => '<='], |
11 |
];
|
12 |
}
|
Puede ver una lista completa de operadores de comparación disponibles aquí.
A continuación se muestra cómo se ve nuestro formulario cuando el usuario envía un atributo no válido:



Si queremos proporcionar las reglas de restricción específicas en un mensaje de error, los Validadores de Yii le permiten personalizar el error mostrado al usuario, de la siguiente manera:



La implementación de esto es bastante simple con la adición del atributo de mensaje:
1 |
public function rules() |
2 |
{
|
3 |
return [ |
4 |
[['thought'], 'string', 'max' => 255], |
5 |
[['thought'], 'trim'], |
6 |
[['thought'], 'required'], |
7 |
[['captcha'], 'captcha'], |
8 |
[['rank'], 'integer'], |
9 |
['rank', 'compare', 'compareValue' => 0, 'operator' => '>','message'=>Yii::t('app','Rank must be between 0 and 100 inclusive.')], |
10 |
['rank', 'compare', 'compareValue' => 100, 'operator' => '<=','message'=>Yii::t('app','Rank must be between 0 and 100 inclusive.')], |
11 |
];
|
12 |
}
|
Actualización de nuestro esquema para probar más validaciones
Para algunas de estas próximas pruebas de validación, voy a pedirle que agregue algunos campos a la base de datos.
En \migrations\m150219_235923_create_sample_table.php, agregaremos
algunos nuevos campos para probar el siguiente conjunto de validadores:
correo electrónico, URL, nombre de archivo, etc.
1 |
$this->createTable('{{%sample}}', [ |
2 |
'id' => Schema::TYPE_PK, |
3 |
'thought' => Schema::TYPE_STRING.' NOT NULL DEFAULT ""', |
4 |
'goodness' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 0', |
5 |
'rank' => Schema::TYPE_INTEGER . ' NOT NULL', |
6 |
'censorship' => Schema::TYPE_STRING . ' NOT NULL', |
7 |
'occurred' => Schema::TYPE_DATE . ' NOT NULL', |
8 |
'email' => Schema::TYPE_STRING . ' NOT NULL DEFAULT ""', |
9 |
'url' => Schema::TYPE_STRING . ' NOT NULL DEFAULT ""', |
10 |
'filename' => Schema::TYPE_STRING.' NOT NULL', |
11 |
'avatar' => Schema::TYPE_STRING.' NOT NULL', |
12 |
], $tableOptions); |
A continuación, ejecute la migración down para borrar la tabla y luego up para crearla:
1 |
Admins-MBP:hello Jeff$ ./yii migrate/down 1
|
2 |
Yii Migration Tool (based on Yii v2.0.2) |
3 |
|
4 |
Total 1 migration to be reverted: |
5 |
m150219_235923_create_sample_table |
6 |
|
7 |
Revert the above migration? (yes|no) [no]:yes |
8 |
*** reverting m150219_235923_create_sample_table
|
9 |
> drop table {{%sample}} ... done (time: 0.002s) |
10 |
*** reverted m150219_235923_create_sample_table (time: 0.005s) |
11 |
|
12 |
Migrated down successfully. |
13 |
Admins-MBP:hello Jeff$ ./yii migrate/up 1
|
14 |
Yii Migration Tool (based on Yii v2.0.2) |
15 |
|
16 |
Total 1 new migration to be applied: |
17 |
m150219_235923_create_sample_table |
18 |
|
19 |
Apply the above migration? (yes|no) [no]:yes |
20 |
*** applying m150219_235923_create_sample_table
|
21 |
> create table {{%sample}} ... done (time: 0.007s) |
22 |
*** applied m150219_235923_create_sample_table (time: 0.010s) |
23 |
|
24 |
Migrated up successfully. |
Ahora estamos listos para probar los validadores de correo electrónico y URL.
Validadores de correo electrónico y URL
El EmailValidator garantiza que un valor es una dirección de correo electrónico válida y UrlValidator garantiza que un valor esté en formato de URL, p. http://example.com.
Es muy sencillo crear reglas para nuestros nuevos campos de correo electrónico y URL:
1 |
public function rules() |
2 |
{
|
3 |
return [ |
4 |
[['thought'], 'string', 'max' => 255], |
5 |
[['email'], 'email'], |
6 |
[['url'], 'url'], |
Aquí está el código de vista para el formulario. Tenga en cuenta cómo estoy utilizando etiquetas personalizadas para mejorar la usabilidad de la forma:
1 |
<div class="sample-form"> |
2 |
|
3 |
<?php $form = ActiveForm::begin(); ?> |
4 |
<?= $form->errorSummary($model); ?> |
5 |
|
6 |
<?= $form->field($model, 'thought')->textInput(['maxlength' => 255]) ?> |
7 |
|
8 |
<?= $form->field($model, 'email')->textInput()->label(Yii::t('app','Your email address')) ?> |
9 |
|
10 |
<?= $form->field($model, 'url')->textInput()->label(Yii::t('app','Your website')) ?> |
Aquí están los validadores en acción:



Estos son obviamente muy útiles para aplicaciones web.
El validador de existencias
El ExistValidator es muy útil en ciertos escenarios. Puede asegurar que existe un valor en otra tabla. Y se puede utilizar de varias maneras—aquí se dan algunos ejemplos en la documentación:
1 |
// a1 needs to exist
|
2 |
['a1', 'exist'] |
3 |
// a1 needs to exist, but its value will use a2 to check for the existence
|
4 |
['a1', 'exist', 'targetAttribute' => 'a2'] |
5 |
// a1 and a2 need to exist together, and they both will receive error message
|
6 |
[['a1', 'a2'], 'exist', 'targetAttribute' => ['a1', 'a2']] |
7 |
// a1 and a2 need to exist together, only a1 will receive error message
|
8 |
['a1', 'exist', 'targetAttribute' => ['a1', 'a2']] |
9 |
// a1 needs to exist by checking the existence of both a2 and a3 (using a1 value)
|
10 |
['a1', 'exist', 'targetAttribute' => ['a2', 'a1' => 'a3']] |
La documentación de Yii destaca que Exist puede utilizarse para "verificar que una clave foranea contiene un valor que se puede encontrar en la tabla externa".
Para nuestro ejemplo, voy a crear una regla que compruebe que la dirección de correo electrónico en el formulario ya existe en nuestra tabla de usuario registrada. Para ello, utilizamos el targetClass que le indica a Yii qué clase (o tabla de modelos) buscar la dirección de correo electrónico del usuario para su validación.
Aquí está la definición de reglas—tenga en cuenta la inclusión de nuestro modelo User en la parte superior:
1 |
<?php
|
2 |
|
3 |
namespace app\models; |
4 |
|
5 |
use Yii; |
6 |
use yii\models\User; |
7 |
|
8 |
/**
|
9 |
* This is the model class for table "sample".
|
10 |
*
|
11 |
* @property integer $id
|
12 |
* @property string $thought
|
13 |
* @property integer $goodness
|
14 |
* @property integer $rank
|
15 |
* @property string $censorship
|
16 |
* @property string $occurred
|
17 |
*/
|
18 |
class Sample extends \yii\db\ActiveRecord |
19 |
{
|
20 |
public $captcha; |
21 |
|
22 |
/**
|
23 |
* @inheritdoc
|
24 |
*/
|
25 |
public function rules() |
26 |
{
|
27 |
return [ |
28 |
[['thought'], 'string', 'max' => 255], |
29 |
[['email'], 'email'], |
30 |
[['email'], 'exist','targetClass'=>'\app\models\User','message'=>Yii::t('app','Sorry, that person hasn\'t registered yet')], |
31 |
[['url'], 'url'], |
Esto le indica a Yii que consulte la tabla User para asegurarse de que la dirección de correo electrónico proporcionada coincida con un usuario previamente registrado.
Esto es lo que ve en acción:



Puede obtener más información sobre la validación Exist y sus permutaciones aquí.
Los validadores de archivos e imágenes
A continuación, le mostraré ejemplos del FileValidator, que garantiza la existencia, el tipo MIME y el tamaño de un archivo cargado, y ImageValidator, que valida la imagen y sus propiedades.
Para
explorar los validadores de archivo e imagen, veamos un ejemplo de la
serie Construyendo su startup con PHP: Configuración de usuario, Imágenes
de perfil y Detalles de contacto. En ese episodio del modelo UserSettings, estamos permitiendo a los usuarios cargar un archivo para su imagen de perfil.
El atributo image acepta el archivo subido:
1 |
public function rules() |
2 |
{
|
3 |
return [ |
4 |
[['user_id', ], 'required'], |
5 |
[['user_id', ], 'unique'], |
6 |
[['image'], 'safe'], |
7 |
[['image'], 'file', 'extensions'=>'jpg, gif, png'], |
8 |
[['image'], 'file', 'maxSize'=>'100000'], |
9 |
['image', 'image', 'extensions' => 'png, jpg, gif', |
10 |
'minWidth' => 100, 'maxWidth' => 400, |
11 |
'minHeight' => 100, 'maxHeight' => 400, |
12 |
],
|
Los FileValidators están asegurando que la imagen termina en una extensión de imagen adecuada y es menos de 100.000 bytes.
ImageValidator también verifica el tipo de extensión, así como los rangos de anchura y altura para la imagen.
A continuación se muestra un ejemplo de errores generados al cargar una imagen cuyas dimensiones son mayores que 400 x 400 píxeles:



Ese es mi asistente arriba que solía copiar-editar mis tutoriales.
El rango en el validador
También hay el RangeValidator que asegura que un valor está dentro de una lista de entradas permitidas.
Para nuestro ejemplo, vamos a agregar el campo para la censura de nuevo en la forma:
1 |
<div class="sample-form"> |
2 |
|
3 |
<?php $form = ActiveForm::begin(); ?> |
4 |
<?= $form->errorSummary($model); ?> |
5 |
|
6 |
<?= $form->field($model, 'thought')->textInput(['maxlength' => 255]) ?> |
7 |
|
8 |
<?= $form->field($model, 'email')->textInput()->label(Yii::t('app','Your email address')) ?> |
9 |
|
10 |
<?= $form->field($model, 'url')->textInput()->label(Yii::t('app','Your website')) ?> |
11 |
|
12 |
<?= $form->field($model, 'censorship')->textInput() ?> |
13 |
|
14 |
<?= $form->field($model, 'rank')->textInput() ?> |
15 |
|
16 |
<?= $form->field($model, 'captcha')->widget(\yii\captcha\Captcha::classname(), [ |
17 |
// configure additional widget properties here
|
18 |
]) ?> |
A continuación, agregaremos un RangeValidator para que coincida con la respuesta yes o no:
1 |
public function rules() |
2 |
{
|
3 |
return [ |
4 |
[['thought'], 'string', 'max' => 255], |
5 |
['thought', 'match', 'pattern' => '/^[a-z][A-Za-z,;\"\\s]+[!?.]$/i','message'=>Yii::t('app','Your thoughts should form a complete sentence of alphabetic characters.')], |
6 |
[['email'], 'email'], |
7 |
[['email'], 'exist','targetClass'=>'\app\models\User','message'=>Yii::t('app','Sorry, that person hasn\'t registered yet')], |
8 |
[['url'], 'url'], |
9 |
['censorship', 'in', 'range' => ['yes','no','Yes','No'],'message'=>Yii::t('app','The censors demand a yes or no answer.')], |
He aquí un ejemplo de RangeValidator en acción:



El validador de coincidencias de expresiones regulares
A continuación, echemos un vistazo al RegularExpressionValidator, que realiza la validación en función de una condición definida por una expresión regular.
En nuestro ejemplo, estoy usando el siguiente regex para emparejar oraciones completas con caracteres alfabéticos. Esto significa que deben terminar con cualquiera (!,? O.) Y no tienen caracteres numéricos.
1 |
public function rules() |
2 |
{
|
3 |
return [ |
4 |
[['thought'], 'string', 'max' => 255], |
5 |
['thought', 'match', 'pattern' => '/^[a-z][A-Za-z,;\"\\s]+[!?.]$/i','message'=>Yii::t('app','Your thoughts should form a complete sentence of alphabetic characters.')], |
He aquí un ejemplo de entrada de usuario que falla en la prueba debido a los números y la falta de puntuación:



He aquí una oración válida:



Usted también podría estar interesado en Ocho expresiones regulares que usted debe saber (Tuts+) como referencia para los patrones comunes regex.
El validador único
Finalmente, revisemos el UniqueValidator, que asegura que un valor es único dentro de una tabla, como una dirección de correo electrónico o un slug.
He revisado el SluggableBehavior anteriormente en esta serie, que ofrece su propio soporte de unicidad incorporado. Sin embargo, echemos un vistazo a un par de ejemplos más de la serie Construyendo su startup con PHP.
En
la base de código de Meeting Planner (de los episodios de tutoriales
más recientes) del modelo Place (\frontend\models\Place.php),
utilizamos el validador único de varias maneras:
1 |
public function rules() |
2 |
{
|
3 |
return [ |
4 |
[['name','slug'], 'required'], |
5 |
[['place_type', 'status', 'created_by', 'created_at', 'updated_at'], 'integer'], |
6 |
[['name', 'google_place_id', 'slug', 'website', 'full_address', 'vicinity'], 'string', 'max' => 255], |
7 |
[['website'], 'url'], |
8 |
[['slug'], 'unique'], |
9 |
[['searchbox'], 'unique','targetAttribute' => 'google_place_id'], |
10 |
[['name', 'full_address'], 'unique', 'targetAttribute' => ['name', 'full_address']], |
11 |
];
|
12 |
}
|
Primero, usamos la regla única con el slug para aumentar SluggableBehavior, que es redundante; Pero puede ver el formato de validación.
En
segundo lugar, estamos comprobando que los resultados del cuadro de
búsqueda Autocompletar de Google Places hacen que el campo oculto para
google_place_id sea único, ya que todavía no existe en la tabla de
Places. Estamos esencialmente evitando duplicar Google Place IDs.
La
parte importante de esto es que el validador único de Yii2 nos permite
aplicar la singularidad en el campo visible (searchbox) al validarlo en
la columna secundaria devuelta a través de AJAX de Google
(google_place_id).
En tercer lugar, nos aseguramos de que name y full_address sean únicos. En otras palabras, los nombres de lugares duplicados están bien. Puede haber un Starbucks bazillion. Sin embargo, no queremos que nadie entre en la misma ubicación Starbucks dos veces.
Nota: El café Starbucks no es un estimulante efectivo para los desarrolladores de software. Les animo a frecuentar cafés independientes.
He aquí un ejemplo de esto en acción:



¿Que sigue?
Espero que aceptes lo sencillo y útil que son los validadores Yii2 para el desarrollo web. Simplemente no puedo imaginar alguna vez volver al desarrollo de PHP sin la ayuda de un marco.
Vea los próximos tutoriales en mi serie Programación Con Yii2 mientras continúo sumando diferentes aspectos del framework. En el siguiente episodio, voy a revisar las características avanzadas de validación de Yii2, tales como:
- Validación condicional para realizar una regla de validación sólo si un evento específico es verdadero
- Validadores personalizados para crear validaciones esenciales más allá de lo que Yii ofrece fuera de la caja
- Validación
del lado del cliente para hacer uso de la validación JavaScript de
ActiveForm incorporada de Yii sin necesidad de actualizar la página.
- Validación de AJAX para implementar validaciones AJAX de servidor para extender las capacidades de validación de página de JavaScript de cliente de Yii.
- Eventos de validación para anular la validación o realizar funciones específicas antes y / o después de la validación
- Definición de escenarios para aplicar selectivamente reglas para ciertas situaciones
- Validación Ad Hoc para usar reglas de validación independientemente de la presentación de formularios
Acojo con satisfacción las peticiones de temas y de características. Puedes
publicarlos en los comentarios a continuación, ponme en contacto con
@reifman en Twitter o envíame un correo electrónico a Lookahead
Consulting.
Si quieres saber cuándo llega el próximo tutorial de Yii2, también puedes visitar mi página de instructor en Tuts+. Siempre incluye enlaces a mis artículos inmediatamente después de su publicación.
Enlaces relacionados
- Yii2 Guía para validar la entrada de usuario
- Yii2 Guía para los validadores principales
- Validadores Yii2 (Documentación)
- Yii2 Developer Exchange, mi propio sitio de recursos Yii2



