2 December 2009

Lazy load modules bootstrap

Zend Framework
Многие как и я используют Modules ресурс, который позволяет использовать отдельные Bootstrap файлы для каждого модуля. Но этого ресурса есть один недостаток — он всегда загружает все Bootstrap файлы в независимости от того какое модули мы используем в конкретном запросе. Я решил предоставить решение данной проблемы

Для начала слегка изменим сам ресурс
<?php
class System_Application_Resource_Modules extends Zend_Application_Resource_ResourceAbstract
{
public function init()
{
$modulePlugin = new System_Controller_Plugin_ModuleBootstrap();
$modulePlugin->setBootstrap($this->getBootstrap());

$this->getBootstrap()
->bootstrap('FrontController')
->getResource('FrontController')
->registerPlugin($modulePlugin);

return $modulePlugin;
}
}


Код прост до безобразия. Создаем новый Controller Plugin и регистрируем его в фронт контроллер FrontController
Как Вы уже догадались вся «магия» происходит в System_Controller_Plugin_ModuleBootstrap
<?php
class System_Controller_Plugin_ModuleBootstrap extends Zend_Controller_Plugin_Abstract
{
/**
* var Zend_Application_Bootstrap_BootstrapAbstract
*/
protected $_bootstrap = null;

/**
* var array
*/
protected $_bootstrapedModules = array();

/**
* Constructor
* param array $options
**/
public function __construct($options = null) {
if ($options !== null) {
$this->setOptions($options);
}
}

/**
* Implement configurable object pattern
* param array $options
*/
public function setOptions($options)
{
foreach ((array)$options as $name => $value) {
$setter = 'set'.ucfirst($name);
if (is_callable(array($this, $setter))) {
$this->$setter($value);
}
}
}

/**
* Bootstrap setter
*/
public function setBootstrap(Zend_Application_Bootstrap_BootstrapAbstract $bootstrap)
{
$this->_bootstrap = $bootstrap;
}

/**
* get Front Controller
* return Zend_Controller_Front
*/
protected function _getFront()
{
return Zend_Controller_Front::getInstance();
}
/**
* Return is module run
* param string $module
* return bool
*/
public function isBootsraped($module)
{
return isset($this->_bootstrapedModules[$module]);
}


/**
* Get bootstraps that have been run
*
* return Array
*/
public function getExecutedBootstraps()
{
return $this->_bootstrapedModules;
}

/**
* Format a module name to the module class prefix
*
* param string $name
* return string
*/
protected function _formatModuleName($name)
{
$name = strtolower($name);
$name = str_replace(array('-', '.'), ' ', $name);
$name = ucwords($name);
$name = str_replace(' ', '', $name);
return $name;
}

/**
* preDispatch hook
*/
public function preDispatch(Zend_Controller_Request_Abstract $request)
{
$module = $request->getModuleName();
if (empty($module)) {
$module = $this->_getFront()->getDefaultModule();
}

if (! $this->isBootsraped($module)) {
$moduleDirectory = $this->_getFront()->getControllerDirectory($module);
$bootstrapClass = $this->_formatModuleName($module). '_Bootstrap';

if (!class_exists($bootstrapClass, false)) {
$bootstrapPath = dirname($moduleDirectory). '/Bootstrap.php';
if (file_exists($bootstrapPath)) {
$eMsgTpl = 'Bootstrap file found for module "%s" but bootstrap class "%s" not found';
include_once $bootstrapPath;
if (!class_exists($bootstrapClass, false)) {
throw new Zend_Application_Resource_Exception(sprintf(
$eMsgTpl, $module, $bootstrapClass
));
}
} else {
return;
}
}

$moduleBootstrap = new $bootstrapClass($this->_bootstrap);
$moduleBootstrap->bootstrap();
$this->_bootstrapedModules[$module] = $moduleBootstrap;
}

}
}


В плагине обрабатываем событие preDispatch, в котором, загружаем и запускаем Bootstrap для текущего модуля, если он не был загружен до этого.

Для ипользования нашего класса вместо стандартного просто добавим в конфиг путь к нашим классам
pluginPaths.System_Application_Resource = «System/Application/Resource»



Приятного использования
Tags:zend frameworkbootstraplazy load
Hubs: Zend Framework
+4
4.7k 23
Comments 12
Top of the last 24 hours