Compared to Yii, I was surprised that modules in Zend are very hard to implement. What I wanted was a way to initialize my resources using a module specific configuration file; and a way to run code specific for a module (i.e. add actions to an action stack). Thanks to guidelines from Matthew[1] and module configurators from Padraic[2]: I implemented my own module configurator.
Here is my directory structure:
./ application/ configs/ application.ini layouts/ modules/ default/ configs/ module.ini controllers/ forms/ layouts/ library/ Configurator/ Layout.php models/ views/ helpers/ scripts/ Bootstrap.php news/ Bootstrap.php docs/ library/ MyApp/ Controller/ Plugin/ ModuleConfigurator.php public/ tests/Similar from [2], I registered a plugin at Bootstrap.php:
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
protected function _initControllerPlugins()
{
// Register module configurator so that it will run first and initialize the modules
$frontController = Zend_Controller_Front::getInstance();
$frontController->registerPlugin(new MyApp_Controller_Plugin_ModuleConfigurator(),1);
}
}
The Module Configurator does the following:
class MyApp_Controller_Plugin_ModuleConfigurator extends Zend_Controller_Plugin_Abstract
{
protected $_view;
protected function moduleInit($_bootstrap, $_config)
{
// Run resource configurators
$resources = array_keys($_config->resources->toArray());
foreach ($resources as $resourceName)
{
$options = $_config->resources->$resourceName;
$configuratorClass = $this->_view->originalModule . '_Library_Configurator_' . ucfirst($resourceName);
$configurator = new $configuratorClass($options);
$configurator->setBootstrap($_bootstrap);
$configurator->init();
}
// Attach plugins
$plugins = $_config->plugins->toArray();
foreach ($plugins as $pluginName)
{
$frontController = Zend_Controller_Front::getInstance();
$frontController->registerPlugin(new $pluginName());
}
}
public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request)
{
// Get view
$viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
$viewRenderer->init();
$view = $viewRenderer->view;
$this->_view = $view;
// set up common variables for the view
$view->originalModule = $request->getModuleName();
$view->originalController = $request->getControllerName();
$view->originalAction = $request->getActionName();
$front = Zend_Controller_Front::getInstance();
$bootstrap = $front->getParam('bootstrap');
$moduleName = $request->getModuleName();
$moduleDirectory = Zend_Controller_Front::getInstance()->getModuleDirectory($moduleName);
$configPath = $moduleDirectory . DIRECTORY_SEPARATOR . 'configs' . DIRECTORY_SEPARATOR . 'module.ini';
if (file_exists($configPath))
{
if (!is_readable($configPath))
{
throw new Exception('modules.ini is not readable for module "' . $moduleName . '"');
}
$config = new Zend_Config_Ini($configPath, $bootstrap->getEnvironment());
$this->moduleInit($bootstrap, $config);
}
}
}
So basically, what it does is that it reads the module.ini of the module, then init() every resource. Also, attach plugins if given in the module.ini. So a resource initiliazor is just a realization of a Zend_Application_Resource_ResourceAbstract, like below:
class News_Library_Configurator_Layout extends Zend_Application_Resource_ResourceAbstract
{
public function init()
{
$layout = $this->getBootstrap()->getResource('layout');
$layout->setOptions($this->getOptions());
}
}
Here is an example of a module.ini:
[production] resources.layout.layout = "layout" resources.layout.layoutPath = APPLICATION_PATH "/modules/Core/layouts/scripts" plugins[] = "MyApp_Controller_Plugin_ViewSetup"Each module has a specific library by autoloading it from a module bootstrap, like below:
class News_Bootstrap extends Zend_Application_Module_Bootstrap
{
protected function _initLibraryAutoloader()
{
return $this->getResourceLoader()->addResourceType('library','library','Library');
}
}
If all of these seems advanced to you, check out the references below, these guys explained these stuffs in great detail and I don't want to steal their spotlight (actually I'm just too lazy!)If I miss something, just tell me! :)
References:
[1] http://www.weierophinney.net/matthew/archives/234-Module-Bootstraps-in-Zend-Framework-Dos-and-Donts.html
[2] http://blog.astrumfutura.com/2009/09/self-contained-reusable-zend-framework-modules-with-standardised-configurators/
[3] http://framework.zend.com/wiki/pages/viewpage.action?pageId=16023853
[4] http://blog.vandenbos.org/2009/07/07/zend-framework-module-config/
[5] http://binarykitten.me.uk/dev/zend-framework/177-active-module-based-config-with-zend-framework.html