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
   &nbsp;    // 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í.

Ir al siguiente capítulo: Crea y maneja formularios con Zend_Form