Перейти к содержимому

Как найти нужное событие - поиск по ядру и три системы

Ищем событие под конкретную задачу: как найти его имя в коде ядра, посмотреть уже подписанные обработчики и убедиться, что событие приходит с нужными данными.

Что нужно знать заранее

Событий у платформы три системы, и они не заменяют друг друга. Старое ядро, объектные события нового ядра и отдельные события объектной модели живут своими списками обработчиков.

Имя события всегда лежит в коде того модуля, который его вызывает. Поэтому надёжный способ поиска - не список в документации, а поиск вызова по каталогу модуля.

Имена событий подсказывают их поведение. События с приставкой «до» умеют отменять операцию, события с приставкой «после» сообщают о свершившемся факте и отменить уже ничего не могут.

Шаги

  1. Определить модуль, который выполняет нужное действие с данными проекта.
  2. Найти в его коде вызов события и выписать точное имя вместе с аргументами.
  3. Посмотреть, кто уже подписан на это событие в текущем проекте.
  4. Выбрать систему регистрации: старое ядро, новое ядро или объектная модель.
  5. Проверить событие временным обработчиком, который пишет аргументы в журнал.

Решение

Ищем вызов события в коде модуля:

Окно терминала
grep -rn "ExecuteModuleEventEx" /home/bitrix/www/bitrix/modules/sale/lib/order.php | head
grep -rn "new \\\\Bitrix\\\\Main\\\\Event(" /home/bitrix/www/bitrix/modules/catalog/lib/ | head -5
# первый вызов - события старого ядра, второй - события нового ядра

Поиск по коду отвечает точнее любой статьи в интернете. В строке вызова видно и имя модуля, и имя события, и состав аргументов, которые получит обработчик.

Смотрим, кто уже подписан на событие:

print_r(GetModuleEvents('main', 'OnBeforeUserAdd', true));
// третий аргумент возвращает массив, а не выборку с курсором
// в списке видно и модуль-обработчик, и класс с методом, и порядок сортировки

Чужие обработчики объясняют половину странностей проекта. Стороннее решение может уже менять те же данные, и свой код придётся ставить после него по сортировке.

Регистрируем обработчик нового ядра:

/local/php_interface/init.php
\Bitrix\Main\EventManager::getInstance()->addEventHandler('sale', 'OnSaleOrderSaved',
static function (\Bitrix\Main\Event $event): void {
$order = $event->getParameter('ENTITY');
\Bitrix\Main\Diag\Debug::writeToFile($order->getId(), date('H:i:s'), 'events.log');
});
// регистрация живёт один запрос: для модуля берут registerEventHandler

Подписываемся на старое событие совместимым методом:

\Bitrix\Main\EventManager::getInstance()->addEventHandlerCompatible('main', 'OnBeforeUserAdd',
static function (array &$fields): void {
\Bitrix\Main\Diag\Debug::writeToFile(array_keys($fields), 'OnBeforeUserAdd', 'events.log');
});
// у старых событий нет объекта события: аргументы приходят позиционно и по ссылке

Совместимый метод нужен именно старым событиям ядра. Обычная подписка на такое событие получит пустой объект вместо полей, и обработчик тихо ничего не сделает.

Подписываемся на событие объектной модели инфоблока:

\Bitrix\Main\Loader::includeModule('iblock');
$class = \Bitrix\Iblock\Iblock::wakeUp($iblockId)->getEntityDataClass();
\Bitrix\Main\ORM\EventManager::getInstance()->addEventHandler($class::getEntity()->getNamespace(),
$class::getEntity()->getName(), $class::EVENT_ON_AFTER_ADD, $handler);
// события старого ядра инфоблоков этой системой не покрываются

Проверяем событие на живых данных:

Окно терминала
tail -f /home/bitrix/www/events.log
# журнал показывает и факт срабатывания, и состав аргументов события
# пустой журнал после действия означает, что событие выбрано неверно

Типичные проблемы

Обработчик подписан, но ничего не получает.

Старое событие ядра подписано обычным методом нового ядра вместо совместимого. Для событий без объекта события берут совместимый метод регистрации.

Событие найдено в статье, а в коде ядра его нет.

Имя устарело вместе с версией модуля или относится к другой редакции продукта. Имя всегда сверяют поиском по коду того модуля, который стоит на проекте.

Свои изменения полей затирает чужой обработчик.

На то же событие подписано стороннее решение с меньшим индексом сортировки. Порядок смотрят списком обработчиков и задают свой индекс явно.

Обработчик элемента инфоблока не ловит правки из админки.

Подписка сделана на события объектной модели, а админка пишет через старое ядро. Для элементов инфоблоков берут события старого ядра.

Отмена операции в событии не срабатывает.

Выбрано событие «после», которое сообщает о свершившемся действии. Отменять операцию умеют только события с приставкой «до».

Частые вопросы

Где взять полный список событий модуля?

В коде самого модуля: поиском вызовов событий по его каталогу. Списки в интернете отстают от версий и часто относятся к другой редакции.

Чем совместимая регистрация отличается от обычной?

Совместимая передаёт обработчику позиционные аргументы, обычная - объект события. Старые события ядра работают только с совместимым вариантом.

Как узнать, кто ещё подписан на событие?

Печатью списка обработчиков по модулю и имени события. В списке видно класс, метод и порядок сортировки каждого обработчика.

Почему обработчик не ловит правки из административной части?

Скорее всего выбрана не та система событий: админка пишет старым ядром. Для инфоблоков и пользователей берут события старого ядра.

Куда писать регистрацию: в файл инициализации или в модуль?

Разовую подписку - в файл инициализации, постоянную логику - в свой модуль с регистрацией при установке. Так обработчики не теряются при переносе проекта.

Смежное

Первоисточник