该死,我爱我一点点,但我不同意将任务参数和区域(adminhtml | crontab | frontend | global | install)传输到队列的复杂性/脆弱性,尤其是如果该队列将要执行时Magento环境。如果存在需要处理的混合上下文,则队列解决方案是对当前“问题”的重新实现!
我认为队列方法很脆弱。我的观点是,过早加载事件区域根本不是问题。为了解释这一点,让我们备份并查看问题:
在执行范围内过早加载事件区域有什么危险?
为了理解这一点,我们必须检查执行上下文中的事件区域。Matthias,我想您已经知道这一点,但是对于其他人来说很有趣:
在Mage_Core_Model_App::run()
将请求分发到前端控制器之前,将执行数据设置脚本:
public function run($params)
{
$options = isset($params['options']) ? $params['options'] : array();
$this->baseInit($options);
Mage::register('application_params', $params);
if ($this->_cache->processRequest()) {
$this->getResponse()->sendResponse();
} else {
$this->_initModules();
//Global event area is loaded here
$this->loadAreaPart(Mage_Core_Model_App_Area::AREA_GLOBAL, Mage_Core_Model_App_Area::PART_EVENTS);
if ($this->_config->isLocalConfigLoaded()) {
$scopeCode = isset($params['scope_code']) ? $params['scope_code'] : '';
$scopeType = isset($params['scope_type']) ? $params['scope_type'] : 'store';
$this->_initCurrentStore($scopeCode, $scopeType);
$this->_initRequest();
//Data setup scripts are executed here:
Mage_Core_Model_Resource_Setup::applyAllDataUpdates();
}
$this->getFrontController()->dispatch();
}
return $this;
}
在执行数据设置脚本时,将加载全局事件区域。路由上下文事件区域(frontend或adminhtml)稍后被加载,Mage_Core_Controller_Varien_Action::preDispatch()
这是由于路由器匹配了控制器动作(area
名称是通过继承设置的):
public function preDispatch()
{
//...
Mage::app()->loadArea($this->getLayout()->getArea());
//...
}
因此,通常在应用程序初始化期间,仅执行在全局事件区域下配置的观察者。如果安装脚本执行了诸如
$this->loadAreaPart(Mage_Core_Model_App_Area::AREA_ADMINHTML, Mage_Core_Model_App_Area::PART_EVENTS);
那么只有两种危险:
- 观察者已在adminhtml下配置为观察无上下文事件,例如
controller_front_init_before
或controller_front_init_routers
- 该请求是一个前端请求。
#1应该很容易grep。#2是真正的关注点,我认为反射可以解决问题(请注意,我对使用反射没有任何经验):
<?php
//Start setup script as normal
$installer = $this;
$installer->startSetup()
//Load adminhtml event area
Mage::app()->loadAreaPart(
Mage_Core_Model_App_Area::AREA_ADMINHTML,
Mage_Core_Model_App_Area::PART_EVENTS
);
// your setup script logic here
//I hope this isn't a bad idea.
$reflectedApp = new ReflectionClass('Mage_Core_Model_App');
$_areas = $reflectedApp->getProperty('_areas');
$_areas->setAccessible(true);
$areas = $_areas->getValue(Mage::app());
unset($areas['adminhtml']);
$_areas->setValue(Mage::app(),$areas); //reset areas
//End setup script as normal
$installer->endSetup()
我没有对此进行测试,但是它确实删除了adminhtml事件索引和相应的Mage_Core_Model_App_Area
对象。