Guía Zend: Vistas, View Helpers y Layout
Continuamos con el cuarto capítulo de la Guía Zend en el primer capítulo vimos una Introducción y primera aplicación, en el segundo capítulo de Modelos y Zend_Db expliqué la importancia de las bases de datos. El tercer capítulo hablé de Controladores, Front Controller Plugins y Action Helpers, en este capítulo hablaré sobre Vistas, View Helpers y Layout.
Como vimos en capítulos anteriores, la vista es ni más ni menos que un objeto (Zend_View), al que accedemos desde el controlador con $this->view, y desde la vista propiamente dicha con $this. A modo de repaso también recordaremos que asignamos una variable en el controlador con $this->view->bar = “bar”; y en la vista la accedemos con $this->bar. ¿Nada del otro mundo no?
Cuando empezamos a trabajar con ZF surgen dudas sobre como hacer para no repetir cosas en distintas vistas, si hay algo que queremos usar en varios lugares cuál es la forma correcta de hacerlo. En nuestra etapa pre-framework era hacer un include y listo, en este capítulo veremos que para lograr esto tenemos a nuestra disposición los View Helpers.
Creando un View Helper
Los view helpers son clases que extienden de Zend_View_Helper_Abstract, cuyo nombre tiene el formato ‘Zend_View_Helper_NombreDelHelper’. Los helpers van dentro de la carpeta helpers del módulo correspondiente, y el nombre del archivo es ‘NombreDelHelper.php’. Invocarlo es tan simple como hacer $this->nombreDelHelper(). Obviamente el helper debe implementar un método público llamado nombreDelHelper().
Veamos un ejemplo:
// helper que muestra un mensaje de error // application/views/helpers/ErrorBox.php class Zend_View_Helper_ErrorBox extends Zend_View_Helper_Abstract { public function errorBox($msg) { return "<div class='error'>$msg</div>"; } } // en la vista echo $this->errorBox("Ocurrió un error");
Tips a tener en cuenta
En los view helpers no hay que hacer echo’s, lo correcto es retornar el contenido y hacer el echo en la vista.
public function errorBox($msg) { /* esto esta mal */ echo "<div class='error'>$msg</div>"; /* esto esta bien */ return "<div class='error'>$msg</div>"; }
Hay una regla práctica que dice que, si un view helper se llama sin parámetros, entonces se devuelve una instancia de si mismo. Supongamos el ejemplo anterior, pero ahora no queremos tener un view helper que muestre mensajes de error, otro que muestre mensajes de éxito, etc., sino que queremos un solo helper que se encargue de todo, ¿cómo lo hacemos?
Una solución es pasarle al helper dos parámetros, uno el mensaje que queremos mostrar y otro el tipo de mensaje, o sino crear un método para cada tipo de mensaje:
class Zend_View_Helper_Messages extends Zend_View_Helper_Abstract { public function messages() { return $this; } public function error($msg) { return "<div class='error'>$msg</div>"; } public function success($msg) { return "<div class='success'>$msg</div>"; } }
Entonces este helper lo llamamos:
echo $this->messages()->error("Ocurrio algun error"); echo $this->messages()->success("Todo salio correctamente!");
Desde el view helper podemos acceder a la vista con $this->view, ¿para que queremos hacer esto? el caso mas común es para ejecutar un view helper desde otro view helper, por ejemplo:
class Zend_View_Helper_Ejemplo extends Zend_View_Helper_Abstract { public function ejemplo() { // $html contendrá el html generado a lo largo del helper y que luego sera retornado a la vista $html = ""; .... $html .= $this->view->messages()->success("Todo parece ir bien"); .... return $html; } }
Pero, también hay otro uso que es para acceder a variables que fueron agregadas a la vista:
// en el controlador $this->view->idUsuario = $idUsuario; // en el helper public function ejemplo() { $idUsuario = $this->view->idUsuario; }
Pero esta no es una buena práctica ya que, como vamos a ver el día que queramos testear nuestras aplicaciones por ejemplo con phpUnit, se produce un acoplamiento tal que nos impide testear nuestra aplicación, así que lo correcto es hacer:
// en el controlador $this->view->idUsuario = $idUsuario; // en la vista $this->ejemplo($this->idUsuario); // en el helper public function ejemplo($idUsuario) { }
Como vemos queda más claro, más limpio y más testeable. Además supongamos que en un momento el helper falla porque la variable $this->view->idUsuario no existe, ¿Cómo sabemos en que momento de la aplicación se esta generando? Así que para hacerlo bien, la recibimos como parámetro y listo.
View Helpers Iniciales
Zend trae por defecto muchos view helpers, vamos a repasar los más usados y ver para que sirven, aunque les recomiendo leer el manual para conocer todos los demás, probablemente algún día necesitarán hacer algo que ya este hecho:
HeadLink
El headlink helper genera tags , a los que le podemos agregar hojas de estilos, favicons, etc. Por ejemplo, en nuestro layout podemos tener:
$this->headLink() ->appendStylesheet('/css/global.css') ->appendStylesheet('/css/forms.css', 'screen', 'IE'); // también podemos agregar css condicionales, por ejemplo para IE // al hacer el echo, el HeadLink genera el html para agregar los view helpers echo $this->headLink();
En nuestras vistas podemos ir agregando los CSS adicionales que usemos
$this->headLink()->appendStylesheet('/css/alta.css');>/pre>>/div> >h4>HeadScript>/h4> >p>Similar al headLink, pero para agregar :>/p> 1$this->headScript()->appendFile('/js/scripts.js'); echo $this->headScript();
HTML Object Helpers
El helper principal es htmlObject(), que nos sirve para agregar objetos de diferentes tipos a nuestra página. Luego tenemos otros 3 helpers que son implementaciones particulares del htmlObject():
- htmlFlash() para agregar archivos flash
- htmlPage() para embeber páginas XHTML
- htmlQuicktime() para agregar un video de quicktime
Así que si queremos agregar un archivo flash a nuestra página hacemos directamente
echo $this->htmlFlash('/flash/flash.swf');
Action View Helper? NO. View Helpers
Dejo para el final un tema importante. El action view helper permite ejecutar un action de un controlador dado y retornar el contenido a la vista actual. En otras palabra, podemos ejecutar desde la vista un action de cualquier módulo. Por ejemplo, tenemos un action que carga un menú, entonces podemos hacer:
echo $this->action('menu', 'miControlador', 'miAction');
A primera impresión es una buena idea ya que podemos reutilizar código, “widgetizar” contenido., etc. Pero la realidad es otra. Desde el lado de rendimiento, ZF tiene que clonar la vista, realizar un dispatch adicional, copiar el request object.
Si el action que llamamos esta en el mismo controlador y tenemos código en algún hook (predispatch, postDispatch, etc) lo estaríamos ejecutando dos veces. Y por otro lado y no menos importante, estamos pasando por alto el modelo MVC (la vista comunicándose con el controlador) y agregando una complejidad innecesaria a nuestro diseño.
Pero si todo esto no termina de convencerlos para dejar de lado dicho helper, a partir de la versión 2.0 de Zend Framework, va a dejar de existir.
¿Cuál es la solución? Muy fácil, creamos un view helper que genere el menú y ya esta:
echo $this->menuLateral();
Así que si estas tentado a usar el action view helper ten la seguridad que estas teniendo un problema de diseño en tu aplicación y que con total seguridad existe una solución alternativa que sea más simple y correcta.
El Layout
Para finalizar hablemos un poco del layout. Zend_Layot implementa el patrón Two Step View, que básicamente lo que hace es permitirnos incluir nuestras vistas dentro de otra vista general que funcione como template del sitio. En el primer artículo ya vimos como hacer para inicializar el layout, ahora que ya sabemos lo que es un view helper y los distintos view helpers que trae zend, veamos como quedaría nuestro layout:
// application/layouts/layout.phtml; <?php echo $this->doctype();?> <html> <head> <?php echo $this->headMeta(); echo $this->headTitle(); echo $this->headScript(); echo $this->headStyle(); ?> </head> <body> <?php // view helper propio para crear el header del sitio echo $this->siteHeader(); ?> <div id="content"> <?php // mostrando el contenido de la vista echo $this->layout()->content; ?> </div> <?php // view helper propio para crear el footer echo $this->siteFooter(); ?> </body> </html>
Lo más importante que vemos es que desde el layout también podemos ejecutar view helpers como si estuviéramos en una vista. Hasta aquí llega este artículo. Hicimos una revisión general y tocamos casi todos los temas, ahora lo que queda es poner en práctica lo aprendido, consultar las dudas y como siempre, leer el manual para encontrar todo lo que no pudo entrar aquí.
hola, muchas gracias por esta guía! estoy empezando con ZF y hay mucha documentación, pero se dan algunas cosas por sabidas (o no sé encontrarlas).
Con esta visión global estoy entendiendo cosas que ya he aplicado y me resulta más fácil trabajar y mejorar lo que ya tengo.
buen trabajo!
Hola Rodigo. Muy buena la guia que estás haciendo sobre Zend Framework.
Tengo que comentarte que en algunos puntos se te está desmontando el “SyntaxHighlighter”.
Sigue así, estaré atento a las próximas publicaciones 😉 !
Gracias por los comentarios y por el aviso del SyntaxHighlighter
ya revisamos y corregimos el fallo con el código.
Buenos dias Rodrigo, estuve leyendo tu guia de programación bajo ZF, está interesante pero seria bueno que antes de la configuración nos expliques unos datos técnicos como son requerimientos del servidor, que aplicativos instalar, y como instalar. Es todo cuanto debo agregar por el momento, esperando tu respuesta.
Saludos desde Piura-Perú.
[…] Guía Zend: Vistas, View Helpers y Layout […]
Hola Jack buen punto el que marcas, PHP debe ser version 5.2.4 o superior, en cuanto a las extensiones PHP necesarias en su gran mayoria vienen habilitadas por defecto, en mi caso instale ZF en varios hostings distintos (incluyendo algunos gratuitos :P) y nunca tuve ningun problema
Si quieres ver a fondo los requerimientos puedes consultarlo en http://framework.zend.com/manual/en/requirements.introduction.html
Saludos
Hola Rodrigo,
Me encanta tu guía Zend, pero tengo una duda que no termino de resolver bien. ¿Cómo utilizar distintos layouts en distintos modulos?
Y tengo otra duda, como hacer para que la primera página que aparezca no sea el modulo default, sino otro módulo, para que luego pase al default?
Gracias
Para utilizar distintos layouts en distintos modulos lo mejor es crear un front controller plugin, puedes ver este ejemplo posteado en forosDelWeb http://www.forosdelweb.com/f68/zf-zend_application-modulos-703297/#post2950170
Sobre lo otro, depende que es lo que quieras hacer exactamente, a que te refieres con “que primero cargue un modulo y luego pase al default”?
Si SIEMPRE vas a cargar primero el otro modulo, mejor que ese sea el default entonces no? si es en algunos casos particulares (por ejemplo una landing page que se muestre la primera vez que entras al sitio) una solucion podria ser hacer un _redirect() en caso de que una cookie X no este seteada
Otra solucion interesante seria un front controller plugin que se encargue de setear el modulo/controlador/action a ejecutar, emulando el comportamiento de un _forward
Hola a todos,
Estoy intentando pasar el css a mi proyecto pero no se ve nada. Cuando escribo el css directamente en la pagina si funciona, del resto no se ve nada.
En el controlador escribo lo siguiente:
initView();
$this->view->baseUrl = $this->_request->getBaseUrl();
}
public function ajustarAction()
{
$this->view->titulo = “Ajustar Cuenta”;
$this->view->AjustarCuentaForm = new Default_Form_AjustarCuenta();
}
}
y en el ajustar.phtml escribi:
MIE-> Ajustar Cuenta
<link type="text/css" href="baseUrl?>/css/estilos.css” rel=”stylesheet” />
titulo ;?>
AjustarCuentaForm ;?>
En verdad ya no veo cual es el error, les agradeciria mucho sus sugerencias.
Lo correcto seria hacer en la vista
$this->headLink()->appendStylesheet(“/css/estilos.css”);
Y si son los estilos generales del sitio deberias ponerlo en el layout
Saludos
Gracias rodrigo :)..
Hola Rodrigo como hago para hacer un view helper que esté disponible para todas las vistas, lo que pasa es que tengo una estructura modular y no quiero copiar y pegar el mismo helper (“Archivo BaseUrl.php”) en cada módulo
hola amigo de esta pagina queisiera pedirles una favor recien estoy comensando a aprender a programar en zend zf no se nada ni como comensar quiero aprender como son las aplicaciones y como trabaja soy novato todabia pero tengo muchas ganas de aprender por fa no sean malo espero su respuesta si tienes algunos videos de como desarrollar por fa pasamelo gracias
Ya no he podido seguir el codigo, al hacer echo $this->siteFooter(); no hace nada al igual que siteHeader y eso que tengo creado una vista sitefooter y otra siteHeader, le falta algo al código?? , sería posible subir una versión con los ejemplos??
Gracias y un saludo
Faltan los ejemplos pleaseeeeee
Gracias
Hola Geovanni, me encuentro en la misma situación que tu. Tengo un view Helper en /default que quiero tener disponible en los otros modulos sin tener que copiar y pegar. Has dado con la solución?
saludos!
Hola oye necesito relizar una validacion de 2 tipos de usuarios con frontcontroller podrias ayudarme
Hola
Tengo el mismo problema tambien.
Con el Action View Helper se soluciona ese problema, pero como dicen que penaliza mucho el rendimiento estoy buscando la forma de hacer algo asi como un view helper global accesible para todos los modulos, pero no lo consigo.
Alguna idea?
Al menos en el manual de Zend -> http://framework.zend.com/manual/en/zend.view.helpers.html
No sale nada de que penalice el rendimiento y ademas es la unica opcion que te dan para reutilizar codigo en distintos modulos.