Amazium bvba, your online partner
Zend Framework: route specific layouts
  • Share post with Twitter
  • Share post with StumbleUpon
  • Share post with Delicious
  • Share post with Digg
  • Share post with Technorati
  • Share post with Blinklist
2009-06-21 10:15

Zend Framework: route specific layouts

zend_layout, zend_controller_router, zend framework

I'm playing a bit with how I should organize my application. I don't want to put my admin controllers in a seperate module. This would provide problems when I want to have self-containing modules which contain a front and back-end part.

So, let's go a bit further into this: a module contains a number a controllers and actions. Some are open and others are protected. What better way to arrange this than by using Zend_Acl? For each module you specify the roles/privileges for the controllers and actions. You basically say what type of person can access what kind of functionality. I am still working this out in case you wanted to see the code, so no point in asking (yet).

Having a system to control the rights, we also need a system to display the admin and front-end correctly. Enter the Zend_Layout and routes...

I specified following routes in my main bootstrap (if anyone knows of a shorter way to do this in one line, please let me know):

public function _initAdminRoute()
{
    $this->_bootstrap('frontController');

    $front = $this->getResource('frontController');

    $route = new Zend_Controller_Router_Route(
                    'admin/:module/:controller/:action/*',
                    array('_layout' => 'admin'));
    $front->getRouter()->addRoute('admin_module_controller_action', $route);

    $route = new Zend_Controller_Router_Route(
                    'admin/:module/:controller',
                    array('_layout' => 'admin'));
    $front->getRouter()->addRoute('admin_module_controller', $route);

    $route = new Zend_Controller_Router_Route(
                    'admin/:module',
                    array('_layout' => 'admin'));
    $front->getRouter()->addRoute('admin_module', $route);

    $route = new Zend_Controller_Router_Route(
                    'admin',
                    array('_layout' => 'admin'));
    $front->getRouter()->addRoute('admin', $route);
}

I then created a plugin that would handle the layout change:

<?php

class Amz_Controller_Plugin_Layout extends Zend_Controller_Plugin_Abstract
{

    /**
     * Called before Zend_Controller_Front enters its dispatch loop.
     *
     * @param Zend_Controller_Request_Abstract $request
     * @return void
     */
    public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request)
    {
        $layout_route = $request->getParam('_layout', null);
        $layout_param = $request->getParam('layout', $layout_route);
        if (!is_null($layout_param)) {
            Zend_Layout::getMvcInstance()->setLayout($layout_param);
        }
    }

}

Why the layout and _layout params? Both are used for overriding the default layout. The "layout" param will be used for changing the layout trough the url (i.e. print layout, popup layout,...). The _layout param is for system internal layout changes like the one above. If I would have both called "layout", the system param would override the url entered param. This is not what I strived for.

To get the above plugin working you need to add following line to your application's config file:

resources.frontController.plugins.layout = Amz_Controller_Plugin_Layout

The front-end layout will implement the normal site's layout. The admin's layout will provide links to the main module's admin screens, but also to those defined by the module. I'm thinking of bootstrapping an admin zend_navigation object to do this where the modules add their links to. I haven't worked with Zend_Navigation yet, so I'm still working this out. I want the acl somehow to determine which links should be shown/added so that smart-asses who change the layout by the url don't see a thing they're not supposed to.

Comments and Feedback
"(if anyone knows of a shorter way to do this in one line, please let me know)"

Haven't played w/ Routes in zf 1.8+ but I usually put them in configs/routes.ini which I think looks cleaner.

bingomanatee

2009-11-11 18:29
It is much easier to generalize routes in your config: here is my config.ini:

; ----------- ROUTES ---------------

routes.module_scripts.route = "scripts/:script_module/:script_path"
routes.module_scripts.defaults.controller = "resources"
routes.module_scripts.defaults.action = "script"
routes.module_scripts.defaults.module = "administer"

routes.module_images.route = "images/:image_module/:image_path"
routes.module_images.defaults.controller = "resources"
routes.module_images.defaults.action = "image"
routes.module_images.defaults.module = "administer"

routes.model_css.route = "style/:style_module/:style_path"
routes.model_css.defaults.controller = "resources"
routes.model_css.defaults.action = "css"
routes.model_css.defaults.module = "administer"

routes.admin_mvc.route = "admin/:module/c/:controller/:action/*"
routes.admin_mvc.layout = "admin"
routes.admin.mvc.defaults._layout = "admin"

routes.admin_mv.route = "admin/:module/:action/*"
routes.admin_mv.defaults.controller = "admin"
routes.admin_mv.defaults._layout = "admin"
and the nice, thin resource loader in bootstrap:

protected function _initRoutes()
{
$frontController = Zend_Controller_Front::getInstance();
$router = $frontController->getRouter();
$options = new Zend_Config_Ini(APPLICATION_PATH . DS . 'configs' . DS . 'application.ini', APPLICATION_ENV);
$router->addConfig($options, 'routes');
}

Add a Comment

Your email is never published or shared. Required fields are marked*