事件和事件监听也许是magento中最有趣的功能之一,因为它允许开发者来扩展magento应用程序中的关键部分。
为了为不同模块之间提供更多的灵活性和便利,magento使用了一种事件/监听模式,这种模式允许模块之间进行松散耦合。
在这个系统中有两部分,一部分是事件分发对象和事件信息,另一部分是监听特定的事件。
Magento事件与事件监听
一、事件分发
事 件的创建和分 发使用Mage::dispatchEvent() 函数。核心团队已经在一些核心关键部分创建了一些事件,例如,模型抽象类Mage_Core_Model_Abstract 在一个模型每次保存的时候调用了两个protected函数—— _beforeSave() 和_afterSave() ;在这些方法中有两个事件被触发。
protected function _beforeSave()
{
if (!$this->getId()) {
$this->isObjectNew(true);
}
Mage::dispatchEvent('model_save_before',
array('object'=>$this));
Mage::dispatchEvent($this->_eventPrefix.'_save_before',
$this->_getEventData());
return $this;
}
protected function _afterSave()
{
$this->cleanModelCache();
Mage::dispatchEvent('model_save_after',
array('object'=>$this));
Mage::dispatchEvent($this->_eventPrefix.'_save_after',
$this->_getEventData());
return $this;
}
Mage::dispatchEvent() 方法有两个参数,一个是事件的名称,另一个是保存接受数据的数组。我们可以通过数组传递值或者对象,当我们要处理对象的时候,这个就派上用场了。
为了更清楚的了解事件系统的细节,我们来看一下dispatchEvent() 方法:
public static function dispatchEvent($name, array $data = array())
{
$result = self::app()->dispatchEvent($name, $data);
return $result;
}
这个函数实际上是app核心类Mage_Core_Model_App 中dispatchEvent() 函数的一个别名。
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;
}
dispatchEvent() 方法实际上做了事件/事件监听模型中的所有工作。
- 1. 获取magento的配置对象。
- 2. 遍历事件所有子节点,如果正在监听当前事件就检查
- 3. 对于每一个可用的监听事件,将会尝试实例化监听对象
- 4. 最后,magento将会调用映射到这个特定事件上的监听方法。
二、事件监听绑定
现 在分发事件仅 仅是这个过程的一部分,我们还要告诉magento我们要监听哪个事件,毫无疑问,毫无疑问,我们要通过config.xml来指定。正如我们之前看到 的,dispatchEvent() 方法可以查询到已经配置的监听事件,我们来看一个config.xml的例子。
<events> <event_name>
<observers>
<observer_identifier>
<class>module_name/observer</class>
<method>function_name</method>
</observer_identifier>
</observers>
</event_name>
</events>
event节点可以在任意一个配置部分指定(admin、global、frontend等等),我们可以指定多个event_name子节点,event_name必须要和我们要监听的dispatchEvent() 所使用的事件名称一致。
在每一个event_name 节点中,我们可以包含多个监听,但是每一个要有独特的标识符。
监听节点有两个属性,一个是类<class>,这个点用来指定我们用来监听事件的模型类,另一个是<method>,这个事用来指定实际用来监听事件的方法。我们来分析一个监听类的例子。
class Namespace_Modulename_Model_Observer
{
public function methodName(Varien_Event_Observer $observer)
{
//some code
}
}
关于事件监听模式最有趣的是,不需要继承任何其他的magento的类。