Pragmatism in the real world

Module specific bootstrapping in ZF2

Update
As of Beta 4, this method no longer works. Evan Coury’s post on Module-specific layouts in Zend Framework 2 is the correct way to do this.


Following on from the discussion on modules, we can hook into the event system to do module specific bootstrapping. By this, I mean, if you have some code that you want to run only if the action to be called is within this module, you can hook into the Application‘s dispatch event to achieve this.

As you already know, your module’s init() method enables you to create a hook to the bootstrap event:

module/Simple/Module.php

<?php

namespace Simple;

use Zend\Module\Manager,
Zend\EventManager\Event,
Zend\EventManager\StaticEventManager,
Zend\Module\Consumer\AutoloaderProvider;

class Module implements AutoloaderProvider
{
public function init(Manager $moduleManager)
{
$events = StaticEventManager::getInstance();
$events->attach('bootstrap', 'bootstrap', array($this, 'onBootstrap'));
}

// Assume that getAutoloaderConfig() & getConfig() are defined here

public function onBootstrap(Event $e)
{
$application = $e->getParam('application');
$config = $e->getParam('config');
}
}

The $application has an Event Manager which you can then use to hook into various stages of the routing and dispatch process. So we can create a callback for the dispatch event which occurs just before the controller action is called:


public function onBootstrap(Event $e)
{
$app = $e->getParam('application');
$app->events()->attach('dispatch', array($this, 'onDispatch'), -100);
}

This code will call our module’s onDispatch() method when the dispatch event is fired.

Within our onDispatch(), we do:


public function onDispatch($e)
{
$matches = $e->getRouteMatch();
$controller = $matches->getParam('controller');
if (strpos($controller, __NAMESPACE__) !== 0) {
// not a controller from this module
return;
}

// Do module specific bootstrapping here
}

This code is called after routing has occurred so we can retrieve the RouteMatch object which contains information about the controller and action that is about to be called. We test if the namespace of the controller matches the namespace of the module and if it does not, we return.

If it does, then we are about to dispatch to a controller action within our module and so we run do any specific code that we may wish to.

As an example we could, for instance, change the layout for all actions within this module by accessing the layout view model:


public function onDispatch($e)
{
$matches = $e->getRouteMatch();
$controller = $matches->getParam('controller');
if (strpos($controller, __NAMESPACE__) !== 0) {
// not a controller from this module
return;
}

// Do module specific bootstrapping here

// Set the layout template for every action in this module
$viewModel = $e->getViewModel();
$viewModel->setTemplate('layout/simple');
}

In this case, I have set the layout to layout/simple rather than the default of layout/layout. Of course, you could also set variables into the ViewModel for use in your layout script too.

See also Evan Coury’s Module-specific layouts in Zend Framework 2