Formularios con Zend Framework (Zend_Form)

Una de las características que se había solicitado en Zend Framework era la de poder utilizar formularios. En la versión 1.5 ya existe esta característica; aunque algunas partes de la documentación de Zend es muy vaga el poder de los formularios es excelente; como siempre tiene una muy buena arquitectura que va desde lo medianamente simple para utilizar los formularios de manera rápida hasta lo complejo que permite extender sus capacidades sin ‘hacks’ en el código o rehaciendo partes de código vitales.

Un formulario (Zend_Form) es un contenedor de elementos (por ejemplo una entrada de texto, una casilla de verificación, etc), del lado del controlador debemos definir los elementos, una vez hecho esto entonces podemos visualizar (render) la forma del lado de la vista ya sea asignándole una vista o simplemente con <?=$formulario?> donde $formulario es por supuesto nuestro objeto de tipo Zend_Form

Los elementos que maneja Zend Framework son básicamente los objetos en HTML a los que estamos acostumbrados, pero no estamos limitados a ellos ya que podemos crear los elementos que necesitemos.
Un elemento puede tener validadores (subclases de Zend_Validate_Abstract) que nos permiten validar la entrada, aunque ya existen muchos validadores muy útiles y de uso frecuente.
El elemento puede ser asignado uno o varios “Decoradores“; un Decorador es un objeto que pasa información a un Helper de la vista, los decoradores que tiene Zend Framework integrado nos permiten fácilmente alterar la salida de un elemento y también añadir fácilmente un diseño.

Esquema

El siguiente es un esquema de cómo funciona Zend_Form, podemos ver que el controlador se encargará de crear el formato del formulario y la parte de vista se encargará de mostrar el formulario y de mostrar los errores que hayan surgido.

Esquema de Zend_Form

Crear un formulario

Para crear un formulario debemos hacer lo siguiente:

  1. Crear un formulario (Zend_Form)
  2. Crear elementos ya sea mediante
    $elemento = $formulario->createElement('tipo_elemento', 'nombre_elemento');
    o mediante un objeto de tipo Zend_Form_Element:
    $elemento = new Zend_Form_Element_Text('nombre_elemento');
  3. Asignar propiedades al elemento:
    setLabel('nombre_etiqueta'); //asigna el nombre de la etiqueta del elemento
    setValue('valor'); //asigna el valor del elemento (sobreescribe la entrada del usuario)
    setDecorators($arreglo_decoradores); //asigna los decoradores a usarse
    setRequired(true/false); //indica si el valor no debe estar vacio
    addValidator($validador); //indica el validador a utilizar
  4. Agregar el elemento al formulario:
    $formulario->addElement($elemento);
    los elementos se visualizarán en el orden en que han sido agregados, aunque esto puede cambiarse si se modifica el elemento mediante $elemento->setOrder($numero);
  5. Pasar el formulario a la vista para que sea renderizado:
    $this->view->assign('formulario', $formulario);
  6. Renderizarlo en la vista:
    <?=$this->formulario?>

Validar un formulario

Una vez que hemos renderizado el formulario y el usuario ha enviado datos, lo siguiente que debemos hacer es validar la entrada, para esto debemos de crear nuevamente el formulario y verificar si se han enviado datos (porque Zend Framework solo envia valores y no información sobre el formulario), si se han enviado datos entonces podemos utilizar la función isValid($_POST); que regresará un valor de verdadero en caso de que todos los validadores fueron satisfechos o falso en caso de que alguno no lo fuera.

La ventaja de Zend es que automáticamente agregará un mensaje de error al renderizar el elemento que tuvo un error; inicialmente el código de error estará en inglés, por lo que deberemos de traducir los mensajes (más adelante).

Opciones de Validación

Zend Framework tiene varias opciones para validar las entradas, todas ellas son subclases de Zend_Validate_Abstract, para agregar un validador debemos llamarlo de la siguiente manera:

$elemento->addValidator('nombre_validador', $romper_cadena_al_fallar, $arreglo_opciones);

Los validadores más importantes son (el nombre de validador es el que está entre paréntesis):

  • Zend_Validate_Alnum (alnum)
    Nos permite verificar que la entrada solo contenda caracteres alfanuméricos (letras y dígitos), opcionalmente se le puede pasar como opción un booleano para definir si se deben aceptar espacios en blanco (predeterminado en falso)
  • Zend_Validate_Alpha (alpha)
    Nos permite verificar que la entrada sea sólo letras, al igual que el anterior permite una opción para aceptar espacios en blanco
  • Zend_Validate_Digits (digits)
    Permite verificar que la entrada sea sólo números
  • Zend_Validate_StringLength (stringLength)
    Nos permite definir que la entrada sólo contenga un número mínimo o máximo de valores; que deben ser especificado en las opciones por ejemplo:
    $element->addValidator('stringLength', false, array(3, 20));
    Que especifica una cadena de al menos 3 caracteres y máximo 20 caracteres.
  • Zend_Validate_EmailAddress (emailAddress)
    Es un validador muy poderoso que nos permite verificar que un correo sea válido (al menos en cuanto a formato y servidor válido incluso)
  • Zend_Validate_NotEmpty (notEmpty)
    Este validador nos permite verificar que el usuario ha introducido un valor, lamentablemente no permite eliminar espacios en blanco con trim por ejemplo.

Traducción

Los mensajes de error que mostrará Zend Framework de manera predeterminada serán en inglés; para poderlos mostrar en español debemos utilizar la parte de traducción de Zend (Zend_Translate).

Zend_Translate permite muchas opciones pero aqui haremos una de las más básicas que es mediante un archivo PHP, esto nos permitirá usar las constantes de Zend, para esto simplemente hay que crear un archivo en PHP donde tendrá los mensajes en español, por ejemplo: app/langs/es.php

En este archivo deberemos regresar un arreglo con la llave la cadena a traducir y el valor con la cadena traducida, por ejemplo:

<?php
require_once 'Zend/Validate/NotEmpty.php';
require_once 'Zend/Validate/StringLength.php';
require_once 'Zend/Validate/EmailAddress.php';

return array(
Zend_Validate_NotEmpty::IS_EMPTY => 'El campo no puede estar vacío',
Zend_Validate_StringLength::TOO_LONG => 'El campo debe contener por lo menos %min% caracteres',
Zend_Validate_StringLength::TOO_SHORT => 'El campo debe contener un máximo de %max% caracteres',
Zend_Validate_EmailAddress::INVALID => 'La dirección de correo no es válida',
Zend_Validate_EmailAddress::QUOTED_STRING => "'%localPart%' no concuerda con el formato de comillas",
Zend_Validate_EmailAddress::DOT_ATOM => "'%localPart%' no concuerda con el formato de punto",
Zend_Validate_EmailAddress::INVALID_HOSTNAME => "'%hostname%' no es un nombre de dominio válido",
Zend_Validate_EmailAddress::INVALID_LOCAL_PART => "'%localPart%' no es una parte local válida",
Zend_Validate_EmailAddress::INVALID_MX_RECORD => "'%hostname%' no tiene un dominio de correo asignado",
);

?>

Debemos consultar la API para ver las cadenas que debemos traducir para cada validador. En el ejemplo sólo usaremos tres notEmpty, stringLength y emailAddress

Entonces debemos de asignar estas traducciones a todos los componentes de Zend_Form de la siguiente manera:

$traduccion = new Zend_Translate('array', 'app/langs/es.php', 'es');
Zend_Form::setDefaultTranslator($traduccion);

Obtención de Valores

Los valores del formulario estarán en $_POST['nombre_elemento'] o $_GET['nombre_elemento'] según sea el caso, pero podemos pedirle al formulario que nos regrese solamente los valores que le corresponden de la entrada (si es que pasamos más datos), por lo que debemos hacer:

$valores = $formulario->getValues();

Ejemplo

Para el ejemplo tendremos dos archivos, IndexController.php (Controlador) e index.phtml (vista), simplemente mostraremos un formulario y mostraremos los valores.

El código del ejemplo puede ser obtenido en esta liga:
http://vida.danguer.com/archivos/articulos/Zend_Form/DanguerArticle_Zend_Form.tar.gz

Mientras que el ejemplo puede visualizarse en la siguiente liga:
http://dev.fangit.com/DanguerArticle_Zend_Form/

Temas similares

  • Claudio Salazar

    Hola.

    Excelente aporte, sobre todo pensando que no hay mucho material en español sobre zend_form.

    Un pequeño alcance, al seguir las indicaciones, me surgió un error ya que no encontraba el archivo con las traducciones (es.php), por lo que tuve que dejarlo de la siguiente forma :

    $traduccion = new Zend_Translate(‘array’, ROOT_DIR.’/app/langs/es.php’, ‘es’);
    Zend_Form::setDefaultTranslator($traduccion);

    Por si a alguien más le sucede.

    Saludos!.

  • http://- Gabriel

    Exelente tutorial. Tengo la siguente pregunta, cuando hay un error, se muestra el mensaje, debajo del campo.
    Ahora bien, si quiero que ese mensaje se muestre arriba, o al costado, o agregarle una imagen de error.
    Como Modificarias tu codigo fuente??

  • http://www.danguer.com admin

    Muy buena pregunta, es con Zend_Form_Decorators (decoradores) para resolver tu pregunta hice otro tutorial que lo puedes checar aqui:
    http://vida.danguer.com/2008/08/zend-form-decoradores/

    Espero que te sirva, Saludos

  • Pedro

    Hola,

    buen tutorial, aunque tengo un problema… Los acentos y las ñ no son mostradas correctamente. Puede ser debido al encoding? A alguien mas le ha ocurrido?

    Gracias

  • http://www.danguer.com admin

    Hola Pedro,

    Si, me parece que debe ser un problema del encoding, debes verificar que tanto tu editor, como el html tenga la misma codificación, ya que me parece que esa parte de Zend Framework no realiza operaciones de cadena que pudieran tener problemas con caracteres UTF-8 o ISO-8859-1.

    Checa la parte de tips hasta abajo de este documento:
    http://www.danguer.com/cursos/TecnologiasWeb/2-3-1-Unicode

    Igual y te sirve.

    Saludos!

  • Mictlantecuhtli

    Que tal

    Estoy haciendo pruebas con el manejo de formularios y al aplicar lo descrito respecto a la traducción de mensajes me aparece el siguiente error:
    Debugging information:

    exception ‘Zend_Translate_Exception’ with message ‘Error including array or file ‘es.php” in C:\ZendFramework-1.7.1\library\Zend\Translate\Adapter\Array.php:69
    Stack trace:
    #0 C:\ZendFramework-1.7.1\library\Zend\Translate\Adapter.php(451): Zend_Translate_Adapter_Array->_loadTranslationData(‘es.php’, ‘es’, Array)
    #1 C:\ZendFramework-1.7.1\library\Zend\Translate\Adapter.php(196): Zend_Translate_Adapter->_addTranslationData(‘es.php’, ‘es’, Array)
    #2 C:\ZendFramework-1.7.1\library\Zend\Translate\Adapter.php(109): Zend_Translate_Adapter->addTranslation(‘es.php’, ‘es’, Array)
    #3 C:\ZendFramework-1.7.1\library\Zend\Translate\Adapter\Array.php(47): Zend_Translate_Adapter->__construct(‘es.php’, ‘es’, Array)
    #4 C:\ZendFramework-1.7.1\library\Zend\Translate.php(93): Zend_Translate_Adapter_Array->__construct(‘es.php’, ‘es’, Array)
    #5 C:\ZendFramework-1.7.1\library\Zend\Translate.php(71): Zend_Translate->setAdapter(‘array’, ‘es.php’, ‘es’, Array)
    #6 C:\wamp\www\SAIDxT\application\Initializer.php(103): Zend_Translate->__construct(‘array’, ‘es.php’, ‘es’)
    #7 C:\wamp\www\SAIDxT\application\Initializer.php(78): Initializer->_setTraslation(‘es’)
    #8 C:\wamp\www\SAIDxT\application\bootstrap.php(20): Initializer->__construct(‘development’)
    #9 C:\wamp\www\SAIDxT\html\index.php(12): require(‘C:\wamp\www\SAI…’)
    #10 {main}

  • Mictlantecuhtli

    Listo, el problema que tenía se debia que no reconocía la ruta del archivo es.php.

    Por cierto, una felicitación pues los tips son muy útiles, claros y concisos.

  • http://blog.pablo-morales.com Pablo Morales

    Muy bueno. Saludos.

  • Fernando

    Si usais Zend_Translate con el adaptador csv podeis utilizar Notepad++ para codificar los archivos de texto con las traducciones mediante la opción Formato->Codificar en UTF8. Así no hay problemas con acentos y ñs

  • http://www.reweb.com.ar Joaquín L. Robles

    Tengo un problema un tanto extraño:
    en mi array tengo la traduccion hecha para email no valido de la siguiente forma:

    Zend_Validate_EmailAddress::INVALID => ‘%value% no es una direccion de correo valida’,

    pero por una extraña razon este error siempre es representado como ‘sad’ is not a valid email address in the basic format local-part@hostname, es como que no hiciera el override…

  • Junior

    Hola gracias por el tutorial… Pero tengo un problema.. Cuando creo un primer formulario me crea muy bien pero cuando hago otro formulario totalmente identico y lo llamo desde mi controlador. No me muesta nada y arroja como si no existiera el controlador.