Clase Layout

Caracteristicas de la Clase Layout
La clase Layout es una clase abstracta dentro de agenor, es decir no podremos instanciarla directamente, si no que debemos instanciar a una clase deribada de esta. Layout se encarga de la parte menos dinamica de la pagina, dejando para la clase View (hija), el realizar la parte mas cambiante de la misma.

Dinamizando nuestro layout.phtml
Si analizamos la clase Layout veremos unos metodos que contienen el mismo nombre que las secciones del HTML5, estos son:
header(string $header = 'header.phtml') : void
nav(string $nav = 'nav.phtml') : void
aside(string $aside = 'aside.phtml') : void
footer(string $footer = 'footer.phtml') : void
Si ya te lo estas imaginando, cada uno de esos metodos nos permite cargar una plantilla para el cabezal (header), la barra de navegacion (nav), el lateral (aside) y el pie de pagina (footer).
Tambien como se puede anticipar, se le pasa un parametro que es el archivo que sera tomado como plantilla, que por defecto son header.phtml, nav.phtml, aside.phtml y footer.phtml, que casualmente coinciden con los nombres de nuestro directorio phtml visto en el tema anterior.
Por si acaso y el usuario es muy creativo y crea mediante divs nuevas secciones, la clase layout dispone de un metodo generico para renderizar el layout que deseamos.
Dicho metodo es :
includePhtml(string $dir, string $file) : void
$dir : Directorio donde se encuentra la plantilla.
$file : nombre del archivo sin la extencion phtml.
Entonces con este metodo podremos incluir cualquier plantilla que necesitemos y zanjamos el inconveniente inicial.

Veamos ahora la plantilla con las funcionalidades ya mencionadas.
<!DOCTYPE html>
<html lang="es">
    <head>
        <title>Plantilla Ejemplo</title>
        <!-- METAS -->
        <meta charset="utf-8">
        <meta name="description" content="Agenor: Libreria MVC Basica.">
      <meta name="keywords" content="Agenor, MVC, Libreria" />
       <meta name="author" content="objetivophp@gmail.com">
        <!-- METAS FIN -->
    </head>
    <body>
        <header>
            <?php echo $this->header(); ?>
        </header>
        <nav>
            <?php echo $this->nav(); ?>
        </nav>
        <section>
            <?php echo $this->content(); ?>
        </section>
        <aside>
            <?php echo $this->aside(); ?>
            <?php echo $this->includePhtml('dir''file'); ?>
        </aside>
        <footer>
            <?php echo $this->footer(); ?>
        </footer>
    </body>
</html>
Generalmente el codigo para header, nav, footer son bastantes estaticos aunque se puede otorgar dinamismo, ya sea porque las plantillas phtml pueden contener codigo php o generando varias vistas para cada una de ellas, es decir podriamos tener varios menues o diferentes footer segun la seccion donde estemos, por ejemplo para cambiar el menu:
<?php echo $this->nav($menu); ?> 
y la variable menu debera contener la plantilla de menu que se requiere en cada llamado.

¿ Que paso con la seccion <section>?
Lo que se ve aqui es que todo el contenido desaparecio a favor de una linea php haciendo referencia al metodo content(). Este metodo pertenece a View y es el contenido mas dinamico de la plantilla, hace referencia a las vistas de los modulos y no se encuentran en el directorio layout del sistema. Cada modulo tiene un directorio de vistas DIR_VIEWS (views) y en el una carpeta llamada phtml donde se guardan las mismas.
En definitiva el metodo content, es la salida de la llamada realizada por la url, y como vimos anteriormente si se ejecuta la accion saludoAction, del adaptador HolaMundoAdapter, entonces en el directorio phtml de las vistas del modulo debera existir una plantilla llamada holamundo_saludo.phtml, en caso de no existir deberiamos decirle a la vista que archivo debe renderizar (mostrar).

Cambiando el Layout Principal
Como hemos visto hasta ahora, la plantilla que se usa contiene los llamados a las secciones, las cuales se pueden cambiar por el parametro que ofrece el metodo, pero y el Layout principal, podemos manipularlo.

Efectivamente, la clase layout contiene metodos que nos permiten cambiar en tiempo de ejecucion el mismo o incluso mas que eso cambiar el tema del sitio.
layout() : string / layout(string) : string
el metodo layout() tiene un comportamiento tipo propiedad, si se llama al metodo sin pasar parametro alguno entonces nos retorna el layout o plantilla activa (layout.phtml), pero en caso de pasar un parametro se cambiara a la nueva plantilla, es decir si llamamos a layout('layout_new.phtml); entonces ahora la plantilla activa pasara a ser layout_new.phtml y se retornara el nombre de esta.
Este metodo entonces sirve para ver o cambiar el layout en uso.

layoutDir() : string / layoutDir(string) : string
Tiene el mismo comportamiento que layout(), pero este cambia el directorio del tema, por lo cual debemos tener cuidado que al cambiar el directorio de nuestras plantillas, la plantilla activa exista en el nuevo directorio, de lo contrario debemos configurarla con el metodo layout(). En nuestro esquema visto en el capitulo anterior cambiaria a los temas win8, mint, all, silver que son directorios de diseño o temas.

Luego tenemos 2 metodos accesorios o de apoyo que son:
layoutGetUrl() : string
Nos retorna la url hasta la carpeta de layouts en uso.

layoutGetDir() : string
Nos retorna la ruta hasta el directorio de plantillas en uso.

Layout puede ofrecer algo mas
Como estamos viendo los metodos, header, nav, aside, footer, includePhtml, son para contenidos con un dinamismo BAJO, que generalmente tienen contenido que interesa a todo el sitio, y el metodo content es para contenido con un ALTO dinamismo, y que el contenido esta intimamente relacionado con el adaptador en ejecucion.
Que pasa si nos encontramos en un nivel intermedio, informacion relativa al modulo. Bueno ahi entran en juego los widgets.

WIDGETS
Los widgets, son porciones de codigos embebidos en las clases adaptadoras y que tambien tienen sus vistas, pero a diferencia del contenido generado por content(), que esta ligado a la peticion, los widgets no se relacionan directamente con la peticion y se pueden cargar en cualquier momento dentro de la ejecucion del sistema.

 IMPORTANTE :

Si un widget necesita para ejecutarse determinado recurso, se tendra que asegurar en la ejecucion que este se encuentre disponible o generarlo el mismo para su uso.
Un uso tipico seria mostrar el estado del tiempo, el tipo de cambio, extraidos incluso de otros sitio o mostrar novedades relacionadas con el tema en visualizacion. O sea que un widget contiene un adaptador y una vista, si requiere un modelo el mismo se debe encargar de levantar el recurso.
addWidget(string $nombre, string $modulo, string $adaptador, string $accion) : void
Inserta un widget al Sistema.
$nombre : al widget se le configura un nombre para posible usos posteriores.
$modulo : aqui seteamos el modulo en donde se encuentra el widget, por lo cual podriamos tener un modulo solo con widgets y usarlos de distintos lugares dentro del sistema.
$adaptador : adaptador que se ejecutara.
$accion : accion que se quiere utilizar.
Aqui se puede ver que codigo realizado para nuestro sistema puede convertirse en widget, si nos aseguramos que este tiene disponible los recursos que utiliza.

removeWidget(string $nombre) : void
Quita un widget del sistema, es decir no sera mostrado al renderizar la pantalla.
$nombre : es el nombre del widget que se desea eliminar. Es el parametro $nombre que pusimos en addWidget.

firstWidget(string $nombre) : void
Mueve un widget a la primera posicion.
$nombre : nombre del widget que se renderizara primero.

endWidget(string $nombre) : void
Envia un widget al ultimo lugar de visualizacion.
$nombre : nombre del widget que se renderizara primero.

Como se envia a renderizar el Widget
Hasta aqui vimos como se configura un widget en el sistema, pero este no sera mostrado si no se llama explicitamente al renderizador de widget, pues al no ser una peticion el router no se encarga de ella y ni siquiera sabe que existen widgets. Para realizar el volcado por pantalla del mismo usaremos:
widget(Array $widgetsLoad = array()) : void
el metodo precedente se encarga de poner a funcionar el motor de renderizado de widgets.
$widgetLoad : si no se pasan parametros entonces renderiza todos los widgets cargados en el sistema sistema. Si se envian datos debe ser un arreglo con los nombres de los widgets que seran mostrados.

Los widget se pueden cargar en distintos momentos dentro de la ejecucion del sistema:
<1> en el BootstrapApplication: para ello primero debemos generar la vista del sistema, puesto que el sistema por si solo, la dejara disponible antes de enviar la peticion. Un ejemplo seria:
<?php
// En el BoostrapApplication
public function _startVista()
{
        
$view           = new \agenor\mva\View();
        
$view->layoutDir(\agenor\mva\Registry::get('application')->layout->dir);
        
$view->layout(\agenor\mva\Registry::get('application')->layout->main);
        
$view->addWidget('Cabecera','index','Index','imgCabecera');

        return 
$view;
}


<2> En el bootstrap del modulo, aqui debemos realizar el mismo codigo que en BootstrapApplication, a menos que ya se haya levantado la vista. En ese caso solo hacemos:
a) Si sabemos el nombre del recurso.
\agenor\mva\Registry::get('nombre_recurso')->addWidget('Cabecera','index','Index','imgCabecera');
Si no lo sabemos pero si sabemos que tenemos una vista:
\agenor\mva\Registry::getObjectsType('\agenor\mva\View', true)-> 
                      addWidget('Cabecera','index','Index','imgCabecera')

<3> El ultimo caso es desde el adaptador mismo:
$this->_view->addWidget('Cabecera','index','Index','imgCabecera')

 IMPORTANTE :

Recordar que segun el progreso de ejecucion del sistema, el codigo para levantar el widget cambia y se puede levantar desde BootstrapApplication, pasando por Boostrap del Modulo y por ultimo en el Adaptador en ejecucion.