43.事件分发机制

事件和事件监听也许是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())
    {
        Varien_Profiler::start('DISPATCH EVENT:'.$name);
        $result = self::app()->dispatchEvent($name, $data);
        Varien_Profiler::stop('DISPATCH EVENT:'.$name);
        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>
                <type>singleton/model</type>
                <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 节点中,我们可以包含多
    个监听,但是每一个要有独特的标识符。
这个点用来指定我们用来监听事件的模型类,另一个是<method>,
这个事用来指定实际用来监听事件的方法。我们来分析一个监听类的例子。
class Namespace_Modulename_Model_Observer
{
    public function methodName(Varien_Event_Observer $observer)
    {
        //some code
    }
}

关于事件监听模式最有趣的是,不需要继承任何其他的magento的类。


我们首先看一下Magento系统中预定义了哪些事件:Magento Events , 这个表格有三列,
第一列是事件的名称,比如"customer_login",我们大概知道,
这是用户登录时触发的事件;第二列是事件的作用域,只要有global/frontend/adminhtml这三种,
分别是全局/前台/后台作用域,我们可以指定在哪些作用域响应该事件;
最后一列是相应该事件的模块,比如"customer_login"事件在Catalog,Checkout,Log,Reports,Wishlist这几个模块中都有相应。
如果需要找到触发事件的地方,可以在《Magento Event/Observer Hooks Cheat Sheet》
这个网页中搜索,比如通过查找,
我们可以知道"customer_login"这个事件是在 app/code/core/Mage/Customer/Model/Session.php 
这个文件中触发的,我们打开这个文件,会发现这样的代码:
 public function setCustomerAsLoggedIn($customer)
    {
        $this->setCustomer($customer);
        $this->renewSession();
        Mage::dispatchEvent('customer_login', array('customer'=>$customer));
        return $this;
    }
我们可以发现"customer_login"事件
是在Mage_Customer_Model_Session类的
setCustomerAsLoggedIn()函数中通过
Mage::dispatchEvent()触发的,
同时把customer变量作为参数传递给相应事件的对象。

我们再来分析模块是怎样相应事件的,
仍以"customer_login"这个事件为例,
我们看到Log模块响应了该事件,打开/app/code/core/Mage/Log/etc/config.xml文件,
会看到这样的部分代码:

这里写图片描述

可以看到在Log模块中是在前台相应"customer_login"事件的,
捕捉到这个事件时将执行"log/visitor"
类的"bindCustomerLogin"方法,我们打开/app/code/core/Mage/Log/Model/Visitor.php文件,
将发现这样的代码:
public function bindCustomerLogin($observer)
    {
        if (!$this->getCustomerId() && $customer = $observer->getEvent()->getCustomer()) {
            $this->setDoCustomerLogin(true);
            $this->setCustomerId($customer->getId());
        }
        return $this;
    }
在触发事件时我们使用 Mage::dispatchEvent('customer_login', array('customer'=>$customer)); 
的第二个参数传递变量,在bindCustomerLogin($observer)
函数中使用$observer参数获取该
变量$customer = $observer->getEvent()->getCustomer(),
之后进行相应的扩展。

https://magento2.atlassian.net/wiki/display/m1wiki/Using+the+Event-Observer+Method+in+Magento+1.x

https://magento2.atlassian.net/wiki/display/m1wiki/Magento+1.x+Events+Reference

http://blog.onlinebizsoft.com/magento-observer-events-cheat-sheet-event-listener-reference-list/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值