Dammit, I love me some philwinkle, but I have to disagree with the complexity/brittleness of transporting the task parameters and the area (adminhtml | crontab | frontend | global | install) to a queue, especially if that queue is going to be executing a Magento context. If there are mixed contexts which need handling then the queue solution is a reimplementation of the current "issue"!
I think the queue approach is brittle. My argument is that loading event areas prematurely is not really an issue at all. To explain this, let's back up and look at the problem:
What is the danger of loading an event area prematurely in an execution scope?
To understand this we must examine event areas in the execution context. Matthias, I imagine that you already know this, but for others' edification:
Data setup scripts are executed in Mage_Core_Model_App::run() prior to dispatching the request to the Front Controller:
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;
}
By the time data setup scripts are executing the global event area is loaded. The routing-contextual event areas (frontend or adminhtml) are loaded later on in Mage_Core_Controller_Varien_Action::preDispatch() as a result of router matching a controller action (the area name is set via inheritance):
public function preDispatch()
{
//...
Mage::app()->loadArea($this->getLayout()->getArea());
//...
}
So normally during app initialization only the observers configured under the global event area will be executed. If the setup script does something such as
$this->loadAreaPart(Mage_Core_Model_App_Area::AREA_ADMINHTML, Mage_Core_Model_App_Area::PART_EVENTS);
then there are only two dangers:
- An observer has been misconfigured under adminhtml to observe a context-less event such as
controller_front_init_before or controller_front_init_routers
- The request is a frontend request.
#1 should be easy to grep for. #2 is the real concern, and I think that Reflection can solve the problem (note that I'm woefully inexperienced with using reflection):
<?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()
I've not tested this, but it does remove the adminhtml event index and corresponding Mage_Core_Model_App_Area object.