Обзор системы событий в Magento 2
События в Magento 2 – это очень гибкий способ расширить логику приложения. В сегодняшней статье мы сделаем краткий обзор системы событий, а также увидим, как это работает в Magento 2.
Шаблон наблюдателя (observer)
Основная концепция системы событий такая же, как у старого доброго шаблона программирования для наблюдателей: с ее помощью реализуется у класса механизм, который позволяет объекту этого класса получать оповещения об изменении состояния других объектов и тем самым наблюдать за ними. Шаблон Обсервера (Observer) определяет зависимость «один-ко-многим» между объектами так, что при изменении состояния одного объекта, все зависящие от него объекты уведомляются и обновляются автоматически.
Обычно шаблон представлен двумя объектами: Наблюдателем и Субъектом. Сущность Observer (наблюдателя) прослушивает уведомления Субъекта и выполняет некоторые действия после получения уведомления. А Субъект отвечает за уведомления Наблюдателя: он инкапсулирует информацию о зарегистрированных Наблюдателях и информирует их, когда уведомление было запущено.
Это была общая информация для понимания того, как работает шаблон обсервера. А теперь давайте посмотрим, как это работает на практике в Magento 2.
Система событий в Magento 2
Давайте для практики создадим базовую структуру нашего модуля для обсервера следующим образом:
/{ПАКЕТ_МОДУЛЕЙ}/{МОДУЛЬ}/etc/events.xml /{ПАКЕТ_МОДУЛЕЙ}/{МОДУЛЬ}/Observer/ObserverClass.php
Затем для наблюдения за событиями нам нужно объявить нашего наблюдателя. Объявите наблюдателей и событие в файле events.xml. В новой версии Magento загрузка конфигурации может относиться к различным областям. Все области представлены в виде папок в каталоге etc
, и можно указать конфигурацию events.xml для следующих областей:
adminhtml
– конфигурация будет применена для панели администратора.frontend
– конфигурация будет применена для витрины.crontab
– конфигурация будет применена для действий CRON.webapi_rest
– конфигурация будет применена, когда Magento используется как приложение REST.webapi_soap
– конфигурация будет применена к вызовам SOAP.
Все файлы конфигурации, которые находятся в папке etc
, используются в глобальной области. Глобальные конфигурации загружаются перед конфигурацией конкретных областей и переопределяют их. Для примера мы создадим конфигурацию events.xml в глобальной области.
Давайте посмотрим, как наблюдатели объявляются в events.xml
:
<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd"> <event name="unique_name_of_event"> <observer name="global_event_observer_name" instance="{ПАКЕТ_МОДУЛЕЙ}\{МОДУЛЬ}\Observer\ObserverClass" shared="true" /> </event> </config>
Настройка событий начинается с узла <config>
. Здесь атрибуты задают определение XML схемы, которая должна проверять узлы, вложенные в <config>
. Узлы событий <event>
вложены в узел <config>
. В узле <event>
объявляются наблюдатели (обсерверы), и этот узел может содержать следующие атрибуты:
name
– обязательный атрибут, который идентифицирует узел. Он должен быть уникальным, чтобы предотвратить переопределение узла.instance
– обязательный атрибут, который указывает полное имя класса, который должен быть подписан на уведомления о событиях.shared
– необязательный атрибут, который определяет способ создания класса. Если эта опция не указана (или она имеетfalse
в качестве значения), класс будет создаваться каждый раз, когда происходит событие. В противном случае класс будет разделен между событиями: он будет создан только один раз и сохранен в кеше.disabled
– необязательный атрибут, который дает возможность отключить наблюдателя, если он указан какtrue
.
Итак, мы объявили наш обсервер. Теперь давайте посмотрим, как он может быть реализован:
<?php namespace {ПАКЕТ_МОДУЛЕЙ}\{МОДУЛЬ}\Observer; use Magento\Framework\Event\ObserverInterface; class ObserverClass implements ObserverInterface { public function __construct() { // Объявление зависимостей } public function execute(\Magento\Framework\Event\Observer $observer) { // Код, который нужно выполнить при событии, например: $request = $observer->getRequest(); … return $this; } }
Обратите внимание, что есть одно важное требование: все наблюдатели должны реализовать интерфейс \Magento\Framework\Event\ObserverInterface
. В соответствии с этим в методе ObserverInterface::execute()
должна быть только одна логика наблюдения. В дальнейшей логике метод получает всю информацию о событии из параметров. Одним из параметров является объект класса \Magento\Framework\Event\Observer
. Он может вернуть информацию о событии, используя магические методы (например, геттеры или сеттеры).
Наконец, как Magento 2 запускает события? Все менеджеры событий должны быть реализованы из класса Magento\Framework\Event\ManagerInterface
:
interface ManagerInterface { /** * Отправка события (dispatch event) * Вызывает все обратные вызовы наблюдателей, зарегистрированных для этого события * и других наблюдателей, соответствующих шаблону имени события * * @param string $eventName * @param array $data * @return void */ public function dispatch($eventName, array $data = []); }
Ниже вы можете увидеть логику запуска событий для метода Magento\Framework\Event\Manager::dispatch()
:
class Manager implements ManagerInterface { /** * @param InvokerInterface $invoker * @param ConfigInterface $eventConfig */ public function __construct(InvokerInterface $invoker, ConfigInterface $eventConfig) { $this->_invoker = $invoker; $this->_eventConfig = $eventConfig; } public function dispatch($eventName, array $data = []) { $eventName = mb_strtolower($eventName); foreach ($this->_eventConfig->getObservers($eventName) as $observerConfig) { $event = new \Magento\Framework\Event($data); $event->setName($eventName); $wrapper = new Observer(); $wrapper->setData(array_merge(['event' => $event], $data)); $this->_invoker->dispatch($observerConfig, $wrapper); } } }
Подводя итог, класс менеджера делегирует обработку конфигураций, а наблюдатель делегирует обязанности реализациям интерфейсов ConfigInterface
и InvokerInterface
соответственно. Кроме того, можно запускать пользовательские события (так же, как и в Magento 1.x). Для этого просто внедрите менеджер событий в свой класс и вызовите метод dispatch()
менеджера, когда событие должно быть запущено. Вот пример:
class MyClass { public function __construct(ManagerInterface $eventManager) { // инъекция зависимостей менеджера событий $this->_eventManager = $eventManager; } public function someMethod() { // здесь событие должно быть оправлено $this->_eventManager->dispatch('my_event', array('context' => $this)); } }
В этой статье мы вкратце рассмотрели, как работает система событий в Magento 2. На примере базовой структуры модуля увидели, как это делается на практике. Не стесняйтесь делиться своим мнением или задавать вопросы в разделе комментариев ниже.
Спасибо, что читаете нас!