Antes en este capítulo hemos creado una maqueta común para todas la páginas del sitio web. Pero aún tenemos un par de cosas que hacer para tener una maqueta totalmente funcional. Si recordamos, la plantilla de maqueta contiene una barra de navegación y migas de pan, sin embargo, ambos componentes de interfaz que provee Twitter Bootstrap son actualmente "estáticos" y necesitan ser más interactivos.
Por ejemplo el elemento activo de la barra de navegación debería depender de la acción del controlador que se está ejecutando en el momento. Las migas de pan deberían mostrar la ruta de la página actual. En esta sección dejaremos estos detalles completamente listos para el sitio web con la ayuda de nuestros propios ayudantes de vista.
Un ayudante de vista típico es una clase PHP derivada de la clase base
Zend\View\Helper\AbstractHelper
que a su vez implementa la interfaz
Zend\View\Helper\HelperInterface
(el diagrama de herencia se presenta en
la figura 6.9).
Primero, vamos a implementar la clase para el ayudante de vista Menu
que
imprimirá el código HTML de la barra de navegación. La clase Menu
provee
varios métodos que permiten establecer los elementos del menú en forma de arreglo,
activar el elemento en el menú e imprimir el menú (ver un resumen de los
métodos en la tabla 6.4).
Método | Descripción |
---|---|
__construct($items) |
Constructor de la clase. |
setItems($items) |
Método para colocar los elementos del menú. |
setActiveItemId($activeItemId) |
Método para marcar el elemento activo del menú. |
render() |
Imprime el menú. |
renderItem($item) |
Imprime un solo elemento del menú. |
La información que describe un solo elemento del menú se representará con un arreglo como el que se muestra abajo (por ejemplo, el elemento Home tendrá un ID, una etiqueta y una URL para el hiperenlace):
[
'id' => 'home',
'label' => 'Home',
'link' => $this->url('home')
]
Además, queremos agregar el soporte para el menú desplegable con elementos navegables. Por ejemplo, en el caso del menú desplegable Soporte que tiene los subelementos Documentación y Ayuda la descripción del elemento tomará la forma siguiente:
[
'id' => 'support',
'label' => 'Support',
'dropdown' => [
[
'id' => 'documentation',
'label' => 'Documentation',
'link' => $this->url('doc', ['page'=>'contents'])
],
[
'id' => 'help',
'label' => 'Help',
'link' => $this->url('static', ['page'=>'help'])
]
]
]
Colocaremos la clase Menu
dentro del namespace Application\View\Helper
.
Comenzamos creando el archivo Menu.php
dentro de la carpeta View/Helper
que está dentro de la carpeta fuente del módulo Application (figura 6.10).
¿Por qué colocamos la clase del ayudante de vista dentro de la carpeta fuente del módulo?
Los ayudantes de vista (a diferencia de las plantillas de vista
.phtml
) se guardan dentro de la carpetasrc/
del módulo porque ellas son clases PHP y necesitan ser resueltas por la clase PHP que implementa la característica de autocargado. Por otro lado, las plantillas de vista se resuelven usando una clase especial de ZF3 llamada view resolver, es por esta razón que las plantillas de vista se almacenan dentro de la carpetaview/
del módulo.
Luego creamos el esbozo de código para la clase Menu
:
<?php
namespace Application\View\Helper;
use Zend\View\Helper\AbstractHelper;
// This view helper class displays a menu bar.
class Menu extends AbstractHelper
{
// Menu items array.
protected $items = [];
// Active item's ID.
protected $activeItemId = '';
// Constructor.
public function __construct($items=[])
{
$this->items = $items;
}
// Sets menu items.
public function setItems($items)
{
$this->items = $items;
}
// Sets ID of the active items.
public function setActiveItemId($activeItemId)
{
$this->activeItemId = $activeItemId;
}
}
En el código de arriba definimos varios campos privados para la clase Menu
.
El campo $items
(línea 10) es un arreglo que almacenará la información con
los elementos del menú y el campo $activeItemId
(línea 13) tendrá el ID del
elemento activo en el menú. El elemento del menú activo se verá resaltado.
En las líneas 16-19 definimos el método constructor de la clase que opcionalmente
toma un arreglo de elementos para iniciar el menú. Una manera alternativo para
iniciar el menú es mediante el método setItems()
(líneas 22-25). Y el método
setActiveItemId()
(líneas 28-31) coloca el ID del elemento activo actual.
Luego vamos a agregar el método render()
que generará el código HTML para
la barra de navegación y la regresará como una cadena de texto:
// Renders the menu.
public function render()
{
if (count($this->items)==0)
return ''; // Do nothing if there are no items.
$result = '<nav class="navbar navbar-default" role="navigation">';
$result .= '<div class="navbar-header">';
$result .= '<button type="button" class="navbar-toggle" ';
$result .= 'data-toggle="collapse" data-target=".navbar-ex1-collapse">';
$result .= '<span class="sr-only">Toggle navigation</span>';
$result .= '<span class="icon-bar"></span>';
$result .= '<span class="icon-bar"></span>';
$result .= '<span class="icon-bar"></span>';
$result .= '</button>';
$result .= '</div>';
$result .= '<div class="collapse navbar-collapse navbar-ex1-collapse">';
$result .= '<ul class="nav navbar-nav">';
// Render items
foreach ($this->items as $item) {
$result .= $this->renderItem($item);
}
$result .= '</ul>';
$result .= '</div>';
$result .= '</nav>';
return $result;
}
En el código de arriba producimos el código HTML para el componente que genera
la barra de navegación de Bootstrap. La barra de navegación usará el tema por
defecto y será desplegable (adaptable a los diferentes tamaños de las pantallas).
La barra de navegación no tendrá el texto en la cabecera. En las líneas 22-24
recorremos los elementos del menú e imprimiremos cada uno de ellos con el método
renderItem()
. Finalmente, el método render()
regresa el código HTML
resultante como una cadena de texto.
Para terminar la creación de la clase Menu
vamos a implementar el método
renderItem()
. Este método producirá el código HTML para un solo elemento
del menú:
// Renders an item.
protected function renderItem($item)
{
$id = isset($item['id']) ? $item['id'] : '';
$isActive = ($id==$this->activeItemId);
$label = isset($item['label']) ? $item['label'] : '';
$result = '';
if(isset($item['dropdown'])) {
$dropdownItems = $item['dropdown'];
$result .= '<li class="dropdown ' . ($isActive?'active':'') . '">';
$result .= '<a href="#" class="dropdown-toggle" data-toggle="dropdown">';
$result .= $label . ' <b class="caret"></b>';
$result .= '</a>';
$result .= '<ul class="dropdown-menu">';
foreach ($dropdownItems as $item) {
$link = isset($item['link']) ? $item['link'] : '#';
$label = isset($item['label']) ? $item['label'] : '';
$result .= '<li>';
$result .= '<a href="'.$link.'">'.$label.'</a>';
$result .= '</li>';
}
$result .= '</ul>';
$result .= '</a>';
$result .= '</li>';
} else {
$link = isset($item['link']) ? $item['link'] : '#';
$result .= $isActive?'<li class="active">':'<li>';
$result .= '<a href="'.$link.'">'.$label.'</a>';
$result .= '</li>';
}
return $result;
}
En el código del método renderItem()
de arriba hicimos lo siguiente:
primero revisamos si el elemento es un menú desplegable o un elemento simple
(línea 10). Si el elemento es un menú desplegable recorremos los elementos
que constituyen el menú desplegable e imprimimos cada uno de ellos (líneas 21-28).
Las líneas 35-39 contienen el código HTML para el caso de un elemento simple.
Para poder usar el ayudante de vista Menu
en la plantilla de vista necesitamos
registrarlo en la configuración. Para hacerlo agregamos la llave view_helpers
al archivo module.config.php:
<?php
return [
// ...
// The following registers our custom view
// helper classes in view plugin manager.
'view_helpers' => [
'factories' => [
View\Helper\Menu::class => InvokableFactory::class,
],
'aliases' => [
'mainMenu' => View\Helper\Menu::class
]
],
];
En el código de arriba registramos nuestra clase Menu
como el ayudante de
vista mainMenu
con lo que seremos capaces de acceder a él desde cualquier
template de vista.
Como planeamos usar el ayudante de vista Menu
en la plantilla de maqueta
de vista reemplazamos el código para el menú de navegación que está en el
archivo layout.phtml con el siguiente código:
<!-- Navigation bar -->
<?php
$this->mainMenu()->setItems([
[
'id' => 'home',
'label' => 'Home',
'link' => $this->url('home')
],
[
'id' => 'downloads',
'label' => 'Downloads',
'link' => $this->url("application", ['action'=>'downloads'])
],
[
'id' => 'support',
'label' => 'Support',
'dropdown' => [
[
'id' => 'documentation',
'label' => 'Documentation',
'link' => $this->url('doc', ['page'=>'contents'])
],
[
'id' => 'help',
'label' => 'Help',
'link' => $this->url('static', ['page'=>'help'])
]
]
],
[
'id' => 'about',
'label' => 'About',
'link' => $this->url('about')
],
]);
echo $this->mainMenu()->render();
?>
En el código de arriba accedemos al ayudante de vista registrado mainMenu
y colocamos los elementos de la barra de navegación con la ayuda del método
setItems()
(línea 3). Como parámetro para el método pasamos un arreglo
de elementos. Luego imprimimos la barra de navegación con el método render()
.
Para colocar el elemento activo en la barra de navegación llamamos al
método setActiveItemId()
desde cualquier plantilla de vista. Por ejemplo,
agregamos el siguiente código al comienzo de la plantilla de vista para la
página Acerca de (application/index/about.phtml) de la siguiente manera:
<?php
$this->mainMenu()->setActiveItemId('about');
?>
Ahora si abrimos la página Acerca de en nuestro navegador web deberíamos ver
que el elemento Acerca de (About) del menú de navegación está sombreado con
un color diferente. Para mostrar el elemento activo apropiadamente necesitamos
llamar al método setActivoItemId()
en cada página que este en la barra
de navegación (Home, Descargas, Documentación, etc.) Podemos ver como
se hace esto en la aplicación de ejemplo Hello World.
Ahora que sabemos como implementar un ayudante de vista vamos a crear un segundo
ayudante para imprimir las migas de pan. Es completamente análogo al ayudante
de vista Menu
por esta razón solo mostramos el código completo de la clase
Breadcrumbs
:
<?php
namespace Application\View\Helper;
use Zend\View\Helper\AbstractHelper;
// This view helper class displays breadcrumbs.
class Breadcrumbs extends AbstractHelper
{
// Array of items.
private $items = [];
// Constructor.
public function __construct($items=[])
{
$this->items = $items;
}
// Sets the items.
public function setItems($items)
{
$this->items = $items;
}
// Renders the breadcrumbs.
public function render()
{
if(count($this->items)==0)
return ''; // Do nothing if there are no items.
// Resulting HTML code will be stored in this var
$result = '<ol class="breadcrumb">';
// Get item count
$itemCount = count($this->items);
$itemNum = 1; // item counter
// Walk through items
foreach ($this->items as $label=>$link) {
// Make the last item inactive
$isActive = ($itemNum==$itemCount?true:false);
// Render current item
$result .= $this->renderItem($label, $link, $isActive);
// Increment item counter
$itemNum++;
}
$result .= '</ol>';
return $result;
}
// Renders an item.
protected function renderItem($label, $link, $isActive)
{
$result = $isActive?'<li class="active">':'<li>';
if(!$isActive)
$result .= '<a href="'.$link.'">'.$label.'</a>';
else
$result .= $label;
$result .= '</li>';
return $result;
}
}
Para poder usar el ayudante de vista Breadcrumbs
tenemos que registrarlo en
el archivo module.config.php:
<?php
return [
//...
// The following registers our custom view helper classes.
'view_helpers' => [
'factories' => [
View\Helper\Breadcrumbs::class => InvokableFactory::class,
],
'aliases' => [
'pageBreadcrumbs' => View\Helper\Breadcrumbs::class,
]
],
];
Como planeamos usar el ayudante de vista Breadcrumbs
en la plantilla de maqueta
de vista reemplazamos el código HTML que está en el archivo layout.phtml por
el siguiente código:
<!-- Breadcrumbs -->
<?= $this->pageBreadcrumbs()->render(); ?>
En el código de arriba accedemos al ayudante de vista pageBreadcrumbs()
y
lo llamamos con el método render()
. Luego, el operador echo
imprime el
código HTML de las migas de pan.
Finalmente necesitamos pasar los elementos para las migas de pan en cada plantilla de vista. Es decir, agregamos las siguientes líneas en la plantilla de vista de la página About:
<?php
$this->pageBreadcrumbs()->setItems([
'Home'=>$this->url('home'),
'About'=>$this->url('about'),
]);
?>
Ahora si abrimos la página Acerca de deberíamos ver las migas de como como en la figura 6.11 que está más abajo. Los usuarios del sitio verán fácilmente la página que están visitando y no estarán perdidos.