Retomando el tema de un Layout especifico por cada módulo en Zend framework toca ahora ver como hacer una navegación especifica para cada módulo.
Zend Framework nos permite configurar la nevegación de tres formas distintas:
- Directamente en PHP
- En un fichero XML
- En un fichero .INI
Al principio usaba un fichero XML para conigurar Zend_Navigarion y en el boostrap una función que carga dicho fichero:
protected function _initNavigation(){
$this->bootstrap('layout');
$layout = $this->getResource('layout');
$view = $layout->getView();
$config = new Zend_Config_Xml(APPLICATION_PATH . '/configs/navigation.xml', 'navigation');
$navigation = new Zend_Navigation($config);
Zend_Registry::set('Zend_Navigation', $navigation);
}
Dado que estoy usando Zend_Application para manejar el proyecto tan solo necesito cargar el fichero XML, crear una instanca de Zend_Navigation y luego registrarla con Zend_Registry para que automaticamente la asuma la aplicación y poder usarla desde la vista.
Si tu navegación no es muy larga, tal vez te resulte más práctico usar el ficchero application.ini, pues no tendrás que hacer nada en el bootstrap.
Pero el problema surge, como en todos los otros recursos (Zend_Application_Resource_*), cuando quiero que cada módulo disponga de su propia navegación. Al intentarlo, Zend_Registry siempre se quedará con la última instancia, por lo que todos los módulos tendrán siempre la misma navegación. Esto es por que Zend_Application carga todos los ficheros bootstrap de cada módulo.
Esto es así y seguirá siendo así por que el bootstrap no es el lugar para configurar estos recursos (no lo digo yo). Por esta razón hemos de inicializar todas estas acciones mediante plugins.
Para empezar crearemos la estructura de la naevación en el fichero application.ini:
;Navegación principal
resources.navigation.storage.registry = true
resources.navigation.pages.page001.label = "Home"
resources.navigation.pages.page001.uri = "/"
resources.navigation.pages.page001.controller = "index"
;Navegación Admin
admin.resources.navigation.pages.clients.label = "Clients"
admin.resources.navigation.pages.clients.controller = "clients"
admin.resources.navigation.pages.clients.module = "admin"
admin.resources.navigation.pages.clients.pages.pageA.label = "List"
admin.resources.navigation.pages.clients.pages.pageA.controller = "clients"
admin.resources.navigation.pages.clients.pages.pageA.action = "index"
admin.resources.navigation.pages.clients.pages.pageA.module = "admin"
Es muy importante la primera linea resources.navigation.storage.registry en cada bloque de navegación, sin esto no funcionará. Lo que hace es que nos registra la navegación automáticamente.
Entonces, para inicializar una navegación especifica para cada módulo crearemos un plugin practicamente igual al que comente en el otro post Como hacer un Layout para cada módulo. En mi caso tan solo he de añadir unas lineas:
if(isset($config[$module]['resources']['navigation']['pages'])){
$navigation = new Zend_Navigation($config[$module]['resources']['navigation']['pages']);
Zend_Layout::getMvcInstance()->getView()->navigation($navigation);
}
Si prefieres o ya has creado un fichero XML (mucho más manejable) puedes hacer lo siguiente en lugar de lo anterior:
if(isset($config[$module]['resources']['navigation']['storage']['registry'])){
$configIni = new Zend_Config_Xml(APPLICATION_PATH . '/configs/navigation.' . $module . '.xml', 'navigation');
$navigation = new Zend_Navigation($configIni);
Zend_Layout::getMvcInstance()->getView()->navigation($navigation);
}
De esta forma mi plugin queda de la siguiente manera:
class ZendY_Controller_Plugin_Layout extends Zend_Controller_plugin_Abstract {
public function preDispatch(Zend_Controller_Request_Abstract $request) {
$config = Zend_Controller_Front::getInstance ()->getParam ( 'bootstrap' )->getOptions ();
$module = $request->getModuleName();
if($module === "default") return;
// Helpers Path
Zend_Controller_Action_HelperBroker::addPath ( APPLICATION_PATH . '/modules/' . $module . '/helpers' );
//basePath
if (isset ( $config [$module] ['resources'] ['view'] ['basePath'] )) {
$viewBasePath = $config [$module] ['resources'] ['view'] ['basePath'];
Zend_Layout::getMvcInstance ()->setViewScriptPath ( $viewBasePath );
}
//Layout path
if (isset ( $config [$module] ['resources'] ['layout'] ['layoutPath'] )) {
$layoutPath = $config [$module] ['resources'] ['layout'] ['layoutPath'];
Zend_Layout::getMvcInstance ()->setLayoutPath ( $layoutPath );
}
//LayoutScripts path
if (isset ( $config [$module] ['resources'] ['layout'] ['layout'] )) {
$layoutScript = $config [$module] ['resources'] ['layout'] ['layout'];
Zend_Layout::getMvcInstance ()->setLayout ( $layoutScript );
}
//Navigation
f(isset($config[$module]['resources']['navigation']['storage']['registry'])){
$configIni = new Zend_Config_Xml(APPLICATION_PATH . '/configs/navigation.' . $module . '.xml', 'navigation');
$navigation = new Zend_Navigation($configIni);
Zend_Layout::getMvcInstance()->getView()->navigation($navigation);
}
}
}
Y recordar que para que el plugin funcione debeis regitrar su llamada en el boostrap
protected function _initPlugins(){
$bootstrap = $this->getApplication();
$bootstrap->bootstrap('frontcontroller');
$front = $bootstrap->getResource('frontcontroller');
$front->registerPlugin(new ZendY_Controller_Plugin_Layout());
}
o en el mismo application.ini
resources.frontController.plugins.layout = ZendY_Controller_Plugin_Layout
