Modules in ZF2
A Zend Framework 2 application is made up of a number of modules which each contain the controllers, models, views and other support code required to implement a specific part of the application.
Within a standard ZF2 application, modules live in one of two places:
- /module – for application specific modules
- /vendor – for 3rd party modules
It follows that you are not expected to ever modify 3rd party modules that are stored in /vendor. A good example of a 3rd party module is ZfcUser, which is a generic user registration and authentication module.
Directory organisation
Modules tend to have common directory structures. For a module called Simple, this would be:
The top level of the module contains organisational directories along with the Module.php and autoload_classmap.php files. The directories are:
- config – for configuration files
- src – for PHP classes
- view – for view scripts
You may also see a test and public directory within a module for unit tests and public assets (CSS, JS, images, etc) respectively. Note also that the convention within ZF2 is that folder names are singluar.
As we’re using PHP 5.3, we expect that the classes within the src folder will be namespaced. By default, a module’s main name is assumed to be its main namespace, Simple in this case. In order to make autoloading simpler and to follow the PSR-0 convention, we create the Simple namespace folder within src. This means that the namespace for the class SimpleController is SimpleController within the file src/Simple/Controller/SimpleController.php.
This is obviously one of the more simple modules and it is likely that the src/Simple folder would have other folders such as Model, Form and such like. Also, the view folder would probably have more sub-folders for other controllers.
Set up
Each module is responsible for setting itself up to be ready to use. The Module class is used for this and on startup the Module Manager will call three methods within your Module class:
- getAutoloaderConfig() - to set up the modules' autoloading
- init() - for initialisation
- getConfig() - to provide configuration
getAutoloaderConfig() is the first method called and is expected to return an array suitable for passing to ZendLoaderAutoloaderFactory::factory(). This is used to tell the autoloader where to find the module’s class files.
init() is used for any initialisation required. As getAutoloadConfig() has been run, you can load any other module class, but as getConfig() has not been run yet, you cannot get access to any configuration. As a result, init() is usually used to add events to the EventManager which call back to methods in the Module class later on it the bootstrap process.
getConfig() is expected to return a Traversable (i.e an array or a ZendConfig object) of configuration information that is then merged with all the other configurations from other modules. This merging is what allows for overriding of config in one module by another module.
A bare-bones Module.php
The most simple Module class therefore looks something like this:
namespace Simple;
use ZendModuleManager,
ZendModuleConsumerAutoloaderProvider;
class Module implements AutoloaderProvider
{
public function getAutoloaderConfig()
{
return array(
'ZendLoaderClassMapAutoloader' => array(
__DIR__ . '/autoload_classmap.php',
),
'ZendLoaderStandardAutoloader' => array(
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
),
),
);
}
public function getConfig()
{
return include __DIR__ . '/config/module.config.php';
}
As you can see, getAutoloaderConfig() returns two autoloader configurations for AutoloaderFactory. The first one is a class map file which is fast to load, but needs to be created using bin/classmap_generator.php provided with ZF2. This is usually run during the deployment process. As a result, during development, it is easier to use the StandardAutoloader which maps our Simple namespace to the src/Simple folder and hence allows any class within the Simple namespace to be loaded if it follows PSR-0.
The getConfig() method simply returns an array that’s within config/module.config.php. Initially, this config file usually looks something like this:
return array(
// DI setup
'di' => array(
'instance' => array(
'ZendViewResolverTemplatePathStack' => array(
'parameters' => array(
'paths' => array(
'simple' => __DIR__ . '/../view',
),
),
),
),
),
);
This configuration simply adds our view folder to the top of the list of directories within the TemplatePathStack view resolver. This will allow the view layer to find our view scripts.
It is also common to add routing and other configuration to the module.config.php array.
init()
If you need more code to be executed at startup of your module, then you use the init() method. Typically, the init() method looks something like this:
public function init(Manager $moduleManager)
{
$events = StaticEventManager::getInstance();
$events->attach('bootstrap', 'bootstrap', array($this, 'onBootstrap'));
}
(Don’t forget to add use ZendEventManagerStaticEventManager; at the top of the file.)
This code tells the EventManger to call the onBootstrap() method when the bootstrap event within the ZendMvcBootstrap class is fired. This happens after the Bootstrap class has set up the DI locator, application, router and view objects. Hence, your onBootstrap() method will be called once the getConfig() and getAutoloaderConfig() for all modules have been run and the essential MVC objects for the DI, routing, dispatching and view have all been created.
The bootstrap event passes the application object and the config to your method:
// at top of Module.php:
use ZendEventManagerEvent;
// Within class Module:
public function onBootstrap(Event $e)
{
$application = $e->getParam('application');
$config = $e->getParam('config');
}
As you now have access to the application object, you can also get at the locator and from there you can find interesting things like the view renderer and set the title from a config setting:
// Within class Module:
public function onBootstrap(Event $e)
{
$application = $e->getParam('application');
$config = $e->getParam('config');
$locator = $application->getLocator();
$renderer = $locator->get('ZendViewRendererPhpRenderer');
$title = $config->view->title;
$renderer->headTitle($title);
}
(This obviously assuming that you have a view array with a title element somewhere in your configuration!)
You should now have a good idea of what your Module.php file is for and what can be done with it. The main advantage to modules is that they separate out your code and with a bit of planning, you can re-use them in many applications.