События в Magento 2 – это очень гибкий способ расширить логику приложения. В сегодняшней статье мы сделаем краткий обзор системы событий, а также увидим, как это работает в Magento 2.
Основная концепция системы событий такая же, как у старого доброго шаблона программирования для наблюдателей: с ее помощью реализуется у класса механизм, который позволяет объекту этого класса получать оповещения об изменении состояния других объектов и тем самым наблюдать за ними. Шаблон Обсервера (Observer) определяет зависимость «один-ко-многим» между объектами так, что при изменении состояния одного объекта, все зависящие от него объекты уведомляются и обновляются автоматически.
Обычно шаблон представлен двумя объектами: Наблюдателем и Субъектом. Сущность Observer (наблюдателя) прослушивает уведомления Субъекта и выполняет некоторые действия после получения уведомления. А Субъект отвечает за уведомления Наблюдателя: он инкапсулирует информацию о зарегистрированных Наблюдателях и информирует их, когда уведомление было запущено.
Это была общая информация для понимания того, как работает шаблон обсервера. А теперь давайте посмотрим, как это работает на практике в 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. На примере базовой структуры модуля увидели, как это делается на практике. Не стесняйтесь делиться своим мнением или задавать вопросы в разделе комментариев ниже.
Спасибо, что читаете нас!
WordPress годами был непревзойденным "монолитом": он отвечал и за удобную админ-панель, и за хранение данных,…
В мире веб-серверов часто говорят о противостоянии Nginx vs Apache. Но что, если бы я…
Когда я начинал свой путь в веб-разработке, вопрос "какой веб-сервер использовать?" практически не стоял. Ответ…
Когда речь заходит о веб-серверах, два имени всегда на слуху: Apache и Nginx. Apache —…
В мире веб-разработки мы постоянно сталкиваемся с проблемой: "А у меня на компьютере все работает!".…
На заре моей карьеры веб-разработчика все было относительно просто: установил локальный сервер (помните Denwer?), положил…