Zend framework, como hacer un layout para cada modulo

Si estas usando la última versión de Zend Framework, la 1.9.0, y usas Zend_Application para crear aplicaciones modulares habrás notado que no puedes asignar un layout diferente para cada modulo. Después de buscar y probar diferentes métodos algunos muy complejos y que no se muy bien porque no me funcionaban encontré la solución mezclando todo lo que había visto.

Vamos a suponer que queremos crear un modulo Admin para nuestra aplicación y que usamos la jerarquía de ficheros establecida con Zend Tool. Seguramente nuestro fichero application.ini empezará algo similar a esto:

[production]

phpSettings.display_startup_errors = 0
phpSettings.display_errors = 0

includePaths.library = APPLICATION_PATH "/../library"

bootstrap.path 	= APPLICATION_PATH "/Bootstrap.php"
bootstrap.class = "Bootstrap"

resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts"
resources.layout.layout = layout

resources.view[] =
resources.view.basePath = APPLICATION_PATH "/views/"

Y probablemente querremos añadir un par de lineas para que nuestro Admin tenga su propio layout.

;Modules config
resources.frontController.moduleDirectory = APPLICATION_PATH "/modules"
admin.resources.layout.layoutPath = APPLICATION_PATH "/modules/admin/layouts/scripts"
admin.resources.layout.layout = layout

Claro esta que eso no es suficiente, deberemos añadir:

resources.modules[] =

Este debe ser el primer recurso que cargues, de otra forma no funcionará, para ello colócalo al principio de todo, justo por debajo de [production].

Seguramente, todo esto ya lo has echo y sabes que no funciona, que lo que sucede es que se sobrescribirá el resources.layout.layoutPath y no funcionará. Por ello lo que necesitamos es un Plugin que nos cargue el layout correcto:


// My/Controller/Plugin/Layout.php

class My_Controller_Plugin_Layout extends Zend_Controller_plugin_Abstract{

	public function preDispatch(Zend_Controller_Request_Abstract $request){

        $config = Zend_Controller_Front::getInstance()->getParam('bootstrap')->getOptions();
	$moduleName = $request->getModuleName();

        if (isset($config[$moduleName]['resources']['layout']['layout'])) {

        	$layoutScript = $config[$moduleName]['resources']['layout']['layout'];
                Zend_Layout::getMvcInstance()->setLayout($layoutScript);
        }

        if (isset($config[$moduleName]['resources']['layout']['layoutPath'])) {

              $layoutPath = $config[$moduleName]['resources']['layout']['layoutPath'];
              $moduleDir = Zend_Controller_Front::getInstance()->getModuleDirectory();

              Zend_Layout::getMvcInstance()->setLayoutPath($layoutPath);
        }
    }
}

Y a continuación añadimos a nuestro Bootstrap.php:

protected function _initPlugins(){
		$this->bootstrap('frontController');

		$plugin = new My_Controller_Plugin_Layout();
		$this->frontController->registerPlugin($plugin);
	}

Con esto lo que hacemos es que registrar el plugin para que sea interpretado por el Zend Framework

Dado que he usado el namespace My necesitaré registrarlo en el fichero application.ini añadiendo la siguiente linea:

autoloaderNamespaces[] = "My"

De esta forma mi application.ini de la aplicación, no del módulo quedaría así:

[production]

;First resource to load
resources.modules[] =

phpSettings.display_startup_errors 	= 0
phpSettings.display_errors = 0

includePaths.library = APPLICATION_PATH "/../library"

autoloaderNamespaces[] = "My"

bootstrap.path 	= APPLICATION_PATH "/Bootstrap.php"
bootstrap.class = "Bootstrap"

resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"

resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts"
resources.layout.layout = layout

resources.view[] =
resources.view.basePath = APPLICATION_PATH "/views/"

;Modules config
resources.frontController.moduleDirectory = APPLICATION_PATH "/modules"
admin.resources.layout.layoutPath = APPLICATION_PATH "/modules/admin/layouts/scripts"
admin.resources.layout.layout = layout

Y listo, ya tenemos asignado un layout diferente para nuestro Admin. Para mejorar todo esto sería bueno que las especificaciones de cada módulo se declararán en el fichero application.ini de cada módulo, pero para eso necesitariamos crear un Resource que interpretará cada fichero por separado.



10

Comentarios

  1. Olagato dijó el 20 Agosto de 2009 a las 8:43

    Gracias por el artículo….me ha clarificado muchas cosas. Me parece muy útil. Con el desarrollo Zend Framework veo cada vez más necesaria la separación de modulos: un modulo default para la zona pública y otro módulo admin para la privada. Tu artículo es excelente para realizar el switcher de modulos/layouts. Saludos.

  2. admin dijó el 20 Agosto de 2009 a las 14:46

    ¡Gracias por tu comentario! Espero en breve publicar mas cosas de Zend. Gracias

  3. lisandro dijó el 3 Septiembre de 2009 a las 15:05

    Muy bueno viejo ;)

  4. admin dijó el 3 Septiembre de 2009 a las 18:47

    ¡Muchas Gracias!

  5. Milena dijó el 29 Septiembre de 2009 a las 15:09

    Hola que tal!!! Soy nueva con esto del zend, bale la ultima version y en la parte del layout estoy intentando hacer el ejemplo de la pagina oficial que reaccione lo que tengo en un controlador pero no me funciona, pareciera que no sabe que hay un controlador… Sera que me falta poner algo en aplication.ini? esto es lo que tengo:

    My Site

    layout ()-> content ;

    // fetch ‘foo’ key using placeholder helper:
    echo $this -> placeholder ( ‘Zend_Layout’ )-> foo ;

    echo $this->layout()->title;

    // fetch layout object and retrieve various keys from it:
    $layout = $this -> layout ();
    echo $layout -> bar ;
    echo $layout -> baz ;
    ?>

    y el controlador es el sigiente:

    view->title = ‘Validación’;
    }
    public function barAction()
    {
    $this->view->title = ‘Validación’;
    // disable layouts for this action:
    $this->_helper->layout->disableLayout();
    }

    public function bazAction()
    {
    $this->view->title = ‘Validación’;
    // use different layout script with this action:
    $this->_helper->layout->setLayout(’foobaz’);
    }
    }

    Gracias Hasta Pronto…

  6. admin dijó el 29 Septiembre de 2009 a las 17:17

    Hola, si la documentació de zend deja mucho que desear.
    Ahora mismo no puedo darte mucho detalles del problema ( no estoy en casa ) pero te daré una pista: ActionStacks

  7. Carlos dijó el 9 Octubre de 2009 a las 22:24

    Agradezco sus valiosos aportes en los cuales me han ayudado a despejar dudas acerca del Zend Framework, sin embargo tengo una consulta que espero me pueda ayudar a resolverla.

    En los proyectos que he desarrollado, utilizo el Alias para redireccionar las peticiones a la carpeta /public, y reescribir la url para las funciones que se encuentran en los controladores.

    En la empresa donde trabajo, me configuraron un Alias para mi primer proyecto, pero me dicen que esto fue una excepción y que no me volverán a configurar nuevos alias para nuevas aplicaciones, sino que debo subir mis siguientes desarrollos como “modulos” del primer proyecto.

    Es posible que se pueda configurar mi aplicación inicial para que tenga una estructura:

    http://localhost/programa_default/controller/action // como si nada pasara!!!
    http://localhost/programa_default/programa_2/controller_programa2/action_programa2. // llamando a un segundo programa totalmente distinto!!

    Claro esta, teniendo en cuenta que debo montar mi programa_2 con su public, con sus controllers, con sus modelos, con sus layout. etc, practicamente un programa independiente dentro de otro programa.

    Agradezco tu respuesta y los comentarios con respecto a esta tarea loca que por “politicas” organizacionales colocan conflictos.

  8. admin dijó el 10 Octubre de 2009 a las 0:44

    Hola Carlos,

    A tu pregunta si se puede hacer, es no. No es fácil resolver tu problema de una forma limpia y comoda. Te díria que mejor busques otras opciones. Principalmente el problema ha todo esto es la carpeta public, por las demás no hay problema en replicarlas.

    Tu virtual host o el alias que te han generado solo puede apuntar a una carpeta public por lo que deberias hacer que todas las aplicaciones colgaran en diferntes carpetas dentro de públic y no usar módulos si son aplicaciones independientes.

    No se si alguien podrá aportarte una solución que desconozca, quizás algo con mod_rewrite, no se… pero sea lo que sea, creo merjo será no complicarse la vida. Por eso te recomeindo usar una carpeta para cada aplicación.

    Otra cosa, si para tu trabajo te ponen limitaciones técnicas, pon tu también tus limitaciones ;)

  9. YoGuuu dijó el 24 Enero de 2010 a las 13:25

    Comentar que para mi la linea:

    $moduleDir = Zend_Controller_Front::getInstance()->getModuleDirectory();

    Ha sido innecesaria. Debido a que no se veo que se use en ningún momento.

    He pensado que si la primera comprobación IF del plugin se cambia por esta otra:

    if (isset($config[$moduleName]['resources']['layout']['layout']) && ($config[$moduleName]['resources']['layout']['layout'] != ‘layout’)) {
    // Código aquí
    }

    Solo añadirá el script del layout en caso que este no sea el script por defecto que establece ZF, es decir, por nombre “layout”. Evitando hacer una instancia a objeto innecesaria en esos casos. Es importante si tenemos en cuenta que el layout por defecto será el más usado por norma. Y así también nos podemos ahorrar las lineas del application.ini:

    resources.layout.layout = layout
    admin.resources.layout.layout = layout

    Ya que ZF automáticamente lo coge así para todos los módulos, me he molestado en hacer la comprobación, y el único inconveniente es que si cambias el nombre del layout de una forma no explicita (sin especificar “default.resources…”) este no lo cambiará, por que no asignará ningun layout ya que se basa en modulos y aquí no se especifica a que modulo:

    resources.layout.layout = CustomLayout

    Si se usa la segunda comprobación del IF hay pues, en caso de que se cambie el nombre del layout por defecto hacerlo de forma explicita:

    default.resources.layout.layout = CustomLayout

    Entonces si lo cambiaría…

    Conseguimos dos cosas, que trabaje estrictamente por módulos, pudiendo ponerlos o no. Y si ponemos “layout” (nombre por defecto de los layouts para ZF) o omitimos este dato que no haga de nuevo la asignación y que directamente cargue “layout” para el módulo/path que toke en el segundo IF

    Por último, recalcar que para seguir los coding standards de Zend los bracers “{” y “}” hacen un salto de linea despues de la comprobación.

    A pesar de lo enrrevesado de mis divagaciones… Son sugerencias, no cambios absolutos y necesarios. ¿ Opiniones ?

    Un saludo !!! : )

  10. admin dijó el 24 Enero de 2010 a las 15:47

    Hola YoGuu,

    Si, tienes razón en todo… el código presentado pero no es más que ilustrativo, reducido y funcional. Luego es importante hacerse uno mismo la reflexión que tu has hecho. Mejorar y adaptar a las necesidades de cada uno. Para nada este el código que uso, pues el que suelo usar es algo más largo y hace alunas cosillas más (por seo se me coló la linea innecesaria)

    Lo malo de Zend Framework es su documentación, lo mejor, tal vez, es que todo se puede hacer y rehacer de muchas formas (y creo que por eso la documentación falla mucho, y más ahora con la versión 1.10)

    En cuanto a lo del coding… bueno… soy muy maniático de los estándares, pero odio el formato propuesto por Zend, por lo que en mis trabajos uso el mío propio. Por otra parte, con worpress me suele costar bastante codificar claramente el código, el espacio es limitado y no es fácil tabular…

    Gracias por tu aportación, las aportaciones siempre son bienvenidas!


Deja tu comentario

Trackback URI | RSS de Comentarios

Un poco de html es bueno: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>