教程
本文完整教程地址:https://www.kancloud.cn/yuesir/magento , 希望对 Magento 新手和老手都能有所帮助或者启发。
定义
Magento 中的 Events 和 observers 是对发布-订阅模式的简洁实现。它可以使我们在特定行为触发时抛出一个事件,在响应触发事件过程中调用我们的自定义代码。事件通过 Magento\Framework\Event\Manager 类来分发。它实现了 Magento\Framework\Event\ManagerInterface 接口。
调用调用事件管理对象(eventManager) 的实例的 dispatch 方法来触发事件。第一个参数是触发的事件名称,第二个参数是可选参数,类型是数组,里面可以包含需要传递给监听者的数据。
$this->_eventManager->dispatch(
'customer_register_success',
['account_controller' => $this, 'customer' => $customer]
);
通过 events.xml 来注册观察者,
<event name="customer_register_success">
<observer name="persistent" instance="Magento\Persistent\Observer\RemovePersistentCookieOnRegisterObserver" />
</event>
Magento 中比较重要的事件
在<MAGENTO_DIR> 目录下的 PHP 文件中搜索 eventManager->dispatch 能看到很多事件的例子。我们会重点研究以下的类以及相关事件。
Magento\Framework\App\Action\Action 类中包含以下事件
- controller_action_predispatch
- ‘controlleraction_predispatch‘ . $request->getRouteName()
- ‘controlleraction_predispatch‘ . $request->getFullActionName()
- ‘controlleraction_postdispatch‘ . $request->getFullActionName()
- ‘controlleraction_postdispatch‘ . $request->getRouteName()
- controller_action_postdispatch
Magento\Framework\Model\AbstractModel 中包含以下事件
- model_load_before
- $this->_eventPrefix . ‘_load_before’
- model_load_after
- $this->_eventPrefix . ‘_load_after’
- model_save_commit_after
- $this->_eventPrefix . ‘_save_commit_after’
- model_save_before
- $this->_eventPrefix . ‘_save_before’
- model_save_after
- clean_cache_by_tags
- $this->_eventPrefix . ‘_save_after’
- model_delete_before
- $this->_eventPrefix . ‘_delete_before’
- model_delete_after
- clean_cache_by_tags
- $this->_eventPrefix . ‘_delete_after’
- model_delete_commit_after
- $this->_eventPrefix . ‘_delete_commit_after’
- $this->_eventPrefix . ‘_clear’
Magento\Framework\Model\ResourceModel\Db\Collection 类中包含以下事件
- core_collection_abstract_load_before
- $this->_eventPrefix . ‘_load_before’
- core_collection_abstract_load_after
- $this->_eventPrefix . ‘_load_after’
另外在
- view_block_abstract_to_html_before
- view_block_abstract_to_html_after
- view_message_block_render_grouped_html_after
layout_render_before
‘layoutrender_before‘ . $this->request->getFullActionName()
core_layout_block_create_after
layout_load_before
layout_generate_blocks_before
layout_generate_blocks_after
core_layout_render_element
具体事件相关实现
下面看看
public function afterCommitCallback() {
$this->_eventManager->dispatch('model_save_commit_after', ['object' => $this]);
$this->_eventManager->dispatch($this->_eventPrefix . '_save_commit_after', $this->_getEventData());
return $this;
}
protected function _getEventData() {
return [
'data_object' => $this,
$this->_eventObject => $this,
];
}
这里的 $_eventPrefix 和 $_eventObject 属性在这里十分重要,如果我们看看类似 Magento\Catalog\Model\Product 、Magento\Catalog\Model\Category 、 Magento\Customer\Model\Customer、Magento\Quote\Model\Quote 、Magento\Sales\Model\Order 和其他继承自 Magento\Framework\Model\AbstractModel 的类,都提供了自己的值来覆盖父类的 $_eventPrefix = ‘core_abstract’ 和 $_eventObject = ‘object’, 因此我们可以通过 $this->_eventPrefix . ‘_save_commit_after’ 来指定不同的观察者。
看一个
<config>
<event name="sales_order_save_commit_after">
<observer name="downloadable_observer" instance="Magento\Downloadable\Observer\SetLinkStatusObserver" />
</event>
</config>
观察者放置在 <ModuleDir>/Observer 目录,每个观察者都实现了 Magento\Framework\Event\ObserverInterface 接口的 execute 方法。
class SetLinkStatusObserver implements \Magento\Framework\Event\ObserverInterface {
public function execute(\Magento\Framework\Event\Observer $observer) {
$order = $observer->getEvent()->getOrder();
}
}
编写事件时要注意的点
和 Plugin 一样,实现糟糕的观察者很容易引起 bug, 甚至造成应用崩溃。因此我们要保证我们的监听者足够精简和高效,以免造成性能问题。
事件环路陷阱发生在事件监听者触发了它自己所监听的事件的时候。举个栗子,如果一个观察者监听了 model_save_before 事件,同时监听者内部也尝试保存同一个实体 (entity) 的话,就会造成事件监听环路。
为了使我们的监听者足够明确,我们需要在合适的 scope 下声明它。
仅仅监听前台相关事件,可以在
/etc/frontend/events.xml 中声明观察者 仅仅监听后台相关事件,可以在 /etc/adminhtml/events.xml 中声明观察者 监听全局事件,可以在 /etc/events.xml 中声明观察者