Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

События и наблюдатели

Событие — сообщение «что-то произошло», которое код отправляет в определённый момент: товар открыт, заказ оформлен, покупатель вошёл. Наблюдатель — класс, который подписан на событие и выполняется, когда оно случилось. Так модуль реагирует на действия ядра, не вмешиваясь в его код.

Где лежат файлы

Подписку описывают в файле events.xml, а классы наблюдателей кладут в папку Observer. Оба файла создают вручную.

app/code/Acme/Hello/
├── Observer/
│   └── LogProductView.php      новый файл
└── etc/
    ├── module.xml
    └── frontend/
        ├── events.xml          новый файл
        └── routes.xml

Файл в etc/frontend действует только на витрине, в etc/adminhtml — только в панели, а etc/events.xml — везде.

Подписка

Когда покупатель открывает страницу товара, ядро отправляет событие catalog_controller_product_view. Подпишемся на него:

<?xml version="1.0"?>
<!-- app/code/Acme/Hello/etc/frontend/events.xml -->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="catalog_controller_product_view">
        <observer name="acme_hello_log_product_view" instance="Acme\Hello\Observer\LogProductView"/>
    </event>
</config>

Атрибут name у observer — любое уникальное имя, instance — класс наблюдателя.

Наблюдатель

// app/code/Acme/Hello/Observer/LogProductView.php
namespace Acme\Hello\Observer;
 
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Psr\Log\LoggerInterface;
 
class LogProductView implements ObserverInterface
{
    public function __construct(private LoggerInterface $logger) {}
 
    public function execute(Observer $observer): void
    {
        $product = $observer->getEvent()->getData('product');
 
        $this->logger->info('Просмотр товара: ' . $product->getSku());
    }
}

Выполните bin/magento cache:clean и откройте страницу любого товара: в файле var/log/system.log появится строка с его артикулом. Вместе с событием передаются данные — здесь это товар под ключом product.

Частые события

СобытиеКогда происходитДанные
catalog_controller_product_viewОткрыта страница товараproduct
catalog_product_save_afterТовар сохранёнproduct
checkout_cart_product_add_afterТовар добавлен в корзинуquote_item, product
sales_order_place_afterЗаказ оформленorder
customer_loginПокупатель вошёлcustomer

Какие ещё события есть в ядре, проще всего узнать поиском слова dispatch( по папке vendor/magento.

Своё событие

Модуль может отправлять собственные события, чтобы другие модули могли на них реагировать. Для этого в конструкторе просят Magento\Framework\Event\ManagerInterface:

// app/code/Acme/Hello/Model/Greeter.php
use Magento\Framework\Event\ManagerInterface;
 
public function __construct(private ManagerInterface $eventManager) {}
 
public function greet(string $name): string
{
    $this->eventManager->dispatch('acme_hello_greeted', ['name' => $name]);
 
    return 'Здравствуйте, ' . $name . '!';
}

Наблюдатель, подписанный на acme_hello_greeted, получит имя через $observer->getEvent()->getData('name'). Имя события принято начинать с имени модуля.

Плагин или наблюдатель

СпособКогда подходит
НаблюдательНужно отреагировать на то, что уже произошло
ПлагинНужно изменить аргументы или результат метода

Частая ошибка

В наблюдателе выполняют тяжёлую работу: отправляют письма, обращаются к стороннему сервису. Наблюдатель срабатывает внутри запроса покупателя, и оформление заказа будет ждать, пока он закончит. Такую работу откладывают — в задачу по расписанию или в очередь сообщений, о которых рассказывает урок о расписании.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.