【发布时间】:2011-10-05 07:49:53
【问题描述】:
我的观察者没有被调用。我想知道事件是如何分派的,以便调试它。
【问题讨论】:
-
你能发布你的 config.xml 和包含 Observer 的 Model 类吗?
标签: events magento observer-pattern
我的观察者没有被调用。我想知道事件是如何分派的,以便调试它。
【问题讨论】:
标签: events magento observer-pattern
这里是 Magento 的 Mage_Core_Model_App::dispatchEvent() 调用的细分,这是用来触发事件的。我的 cmets 将在我描述的代码插入之前。我会省略明显的东西。值得一提的是,这是从 Magento Enterprise 1.10.1.1 的角度来看的。
首先,这是整个方法定义:
public function dispatchEvent($eventName, $args)
{
foreach ($this->_events as $area=>$events) {
if (!isset($events[$eventName])) {
$eventConfig = $this->getConfig()->getEventConfig($area, $eventName);
if (!$eventConfig) {
$this->_events[$area][$eventName] = false;
continue;
}
$observers = array();
foreach ($eventConfig->observers->children() as $obsName=>$obsConfig) {
$observers[$obsName] = array(
'type' => (string)$obsConfig->type,
'model' => $obsConfig->class ? (string)$obsConfig->class : $obsConfig->getClassName(),
'method'=> (string)$obsConfig->method,
'args' => (array)$obsConfig->args,
);
}
$events[$eventName]['observers'] = $observers;
$this->_events[$area][$eventName]['observers'] = $observers;
}
if (false===$events[$eventName]) {
continue;
} else {
$event = new Varien_Event($args);
$event->setName($eventName);
$observer = new Varien_Event_Observer();
}
foreach ($events[$eventName]['observers'] as $obsName=>$obs) {
$observer->setData(array('event'=>$event));
Varien_Profiler::start('OBSERVER: '.$obsName);
switch ($obs['type']) {
case 'disabled':
break;
case 'object': case 'model':
$method = $obs['method'];
$observer->addData($args);
$object = Mage::getModel($obs['model']);
$this->_callObserverMethod($object, $method, $observer);
break;
default:
$method = $obs['method'];
$observer->addData($args);
$object = Mage::getSingleton($obs['model']);
$this->_callObserverMethod($object, $method, $observer);
break;
}
Varien_Profiler::stop('OBSERVER: '.$obsName);
}
}
return $this;
}
我们从声明开始。一个特定名称的事件被触发,连同一些可选的支持数据一起包含在内。
public function dispatchEvent($eventName, $args)
{
虽然有些事件有简单的名称,但与控制器相关的预调度和后调度事件等事件不仅会发出一般事件,还会发出特定于控制器的事件。暂时看一下 Mage_Core_Controller_Varien_Action 中的 preDispatch 方法:
Mage::dispatchEvent('controller_action_predispatch', array('controller_action'=>$this));
Mage::dispatchEvent(
'controller_action_predispatch_'.$this->getRequest()->getRouteName(),
array('controller_action'=>$this)
);
Mage::dispatchEvent(
'controller_action_predispatch_'.$this->getFullActionName(),
array('controller_action'=>$this)
同时发出三个不同的事件,您可以在其中任何一个上配置观察者。
接下来,我们循环浏览观察者注册的事件区域和事件。事件区域可以是“前端”或“全局”,但这是您不应该关心的内部概念。
foreach ($this->_events as $area=>$events) {
if (!isset($events[$eventName])) {
获取此事件的派生配置。这本质上是一个 XML 节点,其中包含已通过配置为此事件定义的所有观察者。除非为此事件定义了至少一个观察者,否则不会找到任何配置。在这种情况下,我们将 $this->_events[$area][$eventName] 设置为 FALSE,以后我们将通过上述条件绕过此检查。
$eventConfig = $this->getConfig()->getEventConfig($area, $eventName);
if (!$eventConfig) {
$this->_events[$area][$eventName] = false;
continue;
}
构造一个注册观察者的数组。
$observers = array();
foreach ($eventConfig->observers->children() as $obsName=>$obsConfig) {
$observers[$obsName] = array(
'type' => (string)$obsConfig->type,
'model' => $obsConfig->class ? (string)$obsConfig->class : $obsConfig->getClassName(),
'method'=> (string)$obsConfig->method,
'args' => (array)$obsConfig->args,
);
}
$events[$eventName]['observers'] = $observers;
$this->_events[$area][$eventName]['observers'] = $observers;
}
如果在本轮或之前的轮次中均未找到观察者,则循环。
if (false===$events[$eventName]) {
continue;
否则,准备触发观察者。我们构建了一个 Varien_Event 作为事件的极其简单的容器,并构建了一个 Varien_Event_Observer 来进一步包装它。这作为参数发送给观察者。
} else {
$event = new Varien_Event($args);
$event->setName($eventName);
$observer = new Varien_Event_Observer();
}
现在,循环通过观察者。对于每个观察者,根据其定义的类型(“模型”、单例等)实例化观察者的对象。然后,调用 _callObserverMethod,确保在调用该对象之前存在该对象的方法。注意观察者类型“单例”属于下面的“默认”情况。
foreach ($events[$eventName]['observers'] as $obsName=>$obs) {
$observer->setData(array('event'=>$event));
Varien_Profiler::start('OBSERVER: '.$obsName);
switch ($obs['type']) {
case 'disabled':
break;
case 'object': case 'model':
$method = $obs['method'];
$observer->addData($args);
$object = Mage::getModel($obs['model']);
$this->_callObserverMethod($object, $method, $observer);
break;
default:
$method = $obs['method'];
$observer->addData($args);
$object = Mage::getSingleton($obs['model']);
$this->_callObserverMethod($object, $method, $observer);
break;
}
Varien_Profiler::stop('OBSERVER: '.$obsName);
}
}
return $this;
}
【讨论】:
所有事件都通过Mage::dispatchEvent()。只需 grep 或 ack 获取“dispatchEvent”或您感兴趣的事件名称,您就会看到它被调用的位置。在该行上放置一个断点。
【讨论】: