Guía Zend: Crea y maneja formularios con Zend_Form
Zend_Form es el componente de Zend Framework encargado de crear y manejar los formularios que usemos en nuestras aplicaciones, por lo que es un componente de uso casi obligado en cualquier desarrollo web y uno de los que más llaman la atención al empezar a trabajar con este framework.
Entre su principales responsabilidades se encuentran:
- Validar los formularios y mostrar los errores
- Filtrado (Filter) de datos (escape / normalización de los datos recibidos)
- Generar el HTML Markup del form y sus elementos
Todo esto convierte a Zend_Form en una herramienta realmente simple y potente que nos permitirá ahorrar tiempo al trabajar con formularios y generar un código mucho más pro.
Crear un formulario
Crear un formulario es muy fácil:
$form = new Zend_Form;
Aunque en la práctica lo más limpio es crear una clase propia que extienda de Zend_Form
// application/forms/MyForm.php class MyForm extends Zend_Form { /* método usado para inicializar el form */ public function init() { } } // en el controlador $form = new MyForm;
Setear atributos
Lo más básico es setear el nombre, action, class, etc., lo cual como veremos es muy fácil:
public function init() { $this->setName('frmPrueba') ->;setAction('/process_form.php') ->setEnctype('multipart/form-data') ->setMethod('post') ->setAttrib('class', 'frmClass'); // cualquier atributo html se puede setear con setAttrib() }
Agregando elementos
Zend trae por default los siguientes tipos de elementos:
Button, Checkbox / multiCheckbox, Hidden, Image, Password, Radio, Reset, Select / multi-select, Submit, Text, Textarea.
Hay dos formas de agregar elementos:
// instanciar el elemento y pasárselo al form $form->addElement(new Zend_Form_Element_Text('username'));
// pasar el tipo del elemento al form y que este lo instancie $form->addElement('text', 'username');
En este artículo usaremos la segunda forma cuya sintaxis es:
$form->addElement($elementType, $elementName, array $config);
Como no hay nada mejor que un ejemplo para entender las cosas:
// application/form/Registro.php class Form_Registro extends Zend_Form { public function init() { $this->addElement( 'text', 'nombre', array('required' => true, 'label' => 'Nombre') ); $this->addElement( 'radio', 'sexo', array( 'required' => true, 'label' => 'Sexo', 'multiOptions' => array('h' => 'Hombre', 'm' => 'Mujer') ) ); $this->addElement( 'select', 'como_conociste', array( 'required' => true, 'label' => 'Como nos conociste?', 'multiOptions' => array('1' => 'Por buscadores', '2' => 'Recomendacion') ) ); $this->addElement('submit', 'enviar', array('label' => 'Enviar')); } }
Validando el formulario
Como podrás imaginar, al marcar un campo como ‘required’ lo que hacemos es marcarlo como obligatorio. Controlamos que el formulario haya sido llenado correctamente llamando al método isValid(), en este momento se controla que todos lo campos obligatorios estén completos, además de otras reglas de validación más avanzadas que se pueden crear fácilmente agregando validators a los distintos elementos (validar email, fecha, solo letras, solo números, etc., lo cual luego veremos un poco más en detalle). Si el formulario esta incompleto, automáticamente se agregan lo mensajes de error al markup del form.
// en el controlador if ($this->getRequest()->isPost()) { if ($form->isValid($this->getRequest()->getPost()) { /*
El formulario esta ok (todos los campos obligatorios fueron completados y los validators no arrojaron ningún error), si isValid() devuelve false, se cargan los mensajes de error a los elementos que no estén completados correctamente:
*/ $values = $form->getValues(); $nombre = $form->nombre->getValue(); $sexo = $form->getElement('sexo')->getValue(); } }
Como vemos en el ejemplo, podemos obtener los valores del formulario con getValues(), y obtener el valor de un elemento en particular con getValue(). Podemos acceder al elemento por sobrecarga (magic method __get) o con getElement().
Filters y Validators
Como dijimos más arriba, los filters se encargan de escapar / normalizar los datos recibidos, por ejemplo eliminar todos los números de una cadena de texto, convertir los caracteres extraños a su entidad HTML correspondiente, etc. Se pueden agregar todos los filtros que se desee.
Hay varias formas de agregar un filter a un elemento:
// instanciar el filtro y pasarselo al elemento $element->addFilter(new Zend_Filter_Alnum()); // pasarle el nombre completo $element->addFilter('Zend_Filter_Alnum'); // pasarle el nombre corto $element->addFilter('Alnum'); // al momento de crear el elemento $form->addElement('text', 'nombre', array('filters' => array('Alnum')));
Las últimas formas son más eficientes, ya que Zend no crea inmediatamente la instancia del filtro sino sólo cuando lo vaya a usar (lazy loading), por lo que nos ahorramos generar el objeto innecesariamente con el ahorro de memoria que esto significa, que sea mucho o poco, hace de esta una buena práctica.
Los filtros se aplicarán al momento de hacer el isValid() y cabe aclarar que Zend no modificará la fuente de datos (en este caso $_POST), sino que obtendremos los datos filtrados al pedir los valores con getValues() / getValue(). El tema de los validators es prácticamente igual:
$element->addValidator('Alnum'); $element->addValidator('StringLength', false, array(6, 20)); // al momento de crear el elemento $form->addElement( 'text', 'nombre', array( 'validators' => array( 'Alnum', array('StringLength', false, array(6, 20)) ) ) );
Podemos agregar todos los validators que deseemos, al momento de validar el form se controla que cada validator este ok, si alguno falla entonces falla la validación completa y se muestran los mensajes de error. addValidator() acepta tres parámetros: el primero es el nombre del validator, el segundo es un bool que determina que, si falla este validator, no siga con los demás (true) o que siga (false), y por último un array con los valores que recibe el constructor. En nuestro ejemplo, StringLength recibe la cantidad de letras que se aceptan (entre 6 y 20).
Modificando el HTML Markup
Este primer acercamiento a Zend_Form termina aquí y te dejo el archivo que contiene el código completo para que lo descargues y pruebes.
Por último nos quedaría hablar un poco sobre como modificar el HTML generado por Zend_Form, cómo hacemos si queremos mostrar los elementos dentro de una tabla, ¿en un div? ¿mostrar un elemento al lado del otro? ¿en dos columnas? Todo esto es posible modificando los Decorators de cada elemento y del form, pero este es posiblemente uno de los temas más avanzados de Zend_Form así que requerirá un artículo propio.
Continuando con la guía:
Hasta el momento llevamos 5 capítulos de la serie, te invitamos a revisarlos si aún no lo has hecho:
- Introducción y primera aplicación
- Modelos y Zend_Db
- Controladores, Front Controller Plugins y Action Helpers
- Vistas, View Helpers y Layout
Si te ha gustado la Guía Zend no olvides retwittear para que los amantes de Zend nos ayuden a seguir complementando el contenido.
cual es la función del guion y del ampersand?? -&
Por ejemplo, en estas sentencias:
$element->addValidator(‘StringLength’, false, array(…
$form->
Es un problema del SyntaxHighlighter > es la entidad html de > por lo tanto la sentencia que dices es $form->
Todo lo que veas con > hay que cambiarlo por >
Vaya a mi si que me lo ha traducido, lo que te decía es que & gt; es la entidad html de >, por lo tanto hay que sustituir todos los & gt; por >.
Bueno, yo he trabajado bastante con Zend_Form y me gustaria mucho colaborar con algunos aportes:
1. Hay un problema no tan sencillo de resolver cuando estamos haciendo un formulario de registro para usuarios y queremos validar que las dos contraseñas introducidas, sean identicas. En este caso, podemos enviar el $_POST como parametro al formulario:
No construyo el formulario dentro de init, sino en una funcion dentro de la clase MyForm, digamos
public function loginForm($post = array())
y al instanciar
$form = new MyForm();
$form = $form->loginForm($_POST);
De esta manera, puedo manipular la data que el usuario envía para contruir mi propio validador:
$password = new Zend_Form_Element_Password(‘password’);
$password->setLabel(‘Contraseña’)
->setRequired(true)
->addValidator(‘NotEmpty’)
->addValidator(‘StringLength’, false, array(8));
$value = ”;
if(isset($post[‘password’]))
$value = $post[‘password’];
$identical = new Zend_Validate_Identical($value);
$identical->setMessages(array(
‘notSame’ => ‘Value doesn\’t match!’,
‘missingToken’ => ‘Value doesn\’t match!’
));
$replicate = new Zend_Form_Element_Password(‘replicate’);
$replicate->setLabel(‘Repita la contraseña’)
->setRequired(true)
->addValidator(‘NotEmpty’)
->addValidator(‘StringLength’, false, array(8))
->addValidator($identical);
Mi segundo aporte, es agregarle un captcha sencillo al formulario. Lo primero, es hacer alguna funcion q nos devuelva la ruta absoluta de la carpeta raiz de nuestra instalacion de zend:
public function getRoot() {
// la cantidad de dirname puede variar dependiendo donde este colocada la función
return dirname(dirname(dirname(dirname(__FILE__))));
}
y luego $root = $algunaClase->getRoot();
El captcha necesita dos cosas, un archivo .ttf con una fuente a nuestra elección que es la que se utilizará para el despliegue de la imagen, y una carpeta con permisos de escritura donde colocará las iamgenes generadas “on the fly”
$captcha = new Zend_Form_Element_Captcha(
‘captcha’, // This is the name of the input field
array(‘label’ => ‘¿Eres humano?’,
‘captcha’ => array(
‘captcha’ => ‘Image’,
‘wordLen’ => 4,
‘timeout’ => 300,
‘font’ => $root.’/public/fonts/HirukoBlackAlternate.ttf’,
‘imgDir’ => $root.’/public/captcha/’,
‘imgUrl’ => ‘http://’ . $_SERVER[‘SERVER_NAME’] . ‘/captcha/’,
)));
Ops! Ya lo hemos corregido.
Espero que me ayuden, tengo un problema con las tildes en el formulario y con otros caracteres.
por ejemplo
$this->addElement(‘password’,’passuser’,array(‘label’=>’Contraseña’));
ó
$this->addElement(‘text’,’oracion’,array(‘label’=>’Oración’));
no me muestra el label del elemento en la vista.
Gracias.
muy bien tuto, gracias. Estoy probando hacer primeros pasos con zf.
tengo una pregunta si podrias ayudar me por favor. Con StringTrim borras espacios al principio y al final de la cadena y como reducir espacios en blanco al uno dentro.
Por ejemplo en formulario elemento nombre “Jose _ _ _ Luis” reducir los espacios en uno y grabar en DB, sin aviso de error.
$user_name = new Zend_Form_Element_Text(’nombre’);
$user_name->setLabel(’Name’)
->setRequired(true)
->addValidator(’NotEmpty’, true)
//->addValidator(’regex’, false, array(’/^[a-z]/’))
->addFilter(’StripTags’)
->addFilter(’StringTrim’)
->setAttrib(’size’, 25)
->setAttrib(’maxlength’, 255)
->setOptions(array(’class’=>’text’))
;
He leido usar regex pero no me sale.
gracias