Иногда бывает необходимо повлиять на ход выполнения какого-нибудь процесса, а поскольку изменять ядро продукта запрещено в системе реализован механизм событий. ходе выполнения некоторых API функций или частях системы, в определенных точках установлены вызовы определённых функций, так называемых обработчиков события.
Само событие описывается тремя ключевыми составляющими:
- Модуль, являющийся источником события
- Название события
- Параметры события (аргументы события)
Как это работает?
В разрезе продукта существует глобальный singleton\Bitrix\Main\EventManager
, который хранит все зарегистрированные обработчики событий. Некоторый код инициирует отправку события события, EventManager
выполняет поиск всех обработчиков удовлетворяющих условиям поиска и последовательно(!) в порядке приоритетов и добавления обработчиков передает его в обработчик события.
Что может выступать обработчиком события?
- Callback (php callable тип для которого будет выполнено
call_user_func_array
) - php файл (путь к файлу: TO_PATH - относительный, FULL_PATH абсолютный)
Как подписаться на события?
Существует 2 способа подписки на события: регистрация и добавление. Регистрация обработчика событий осуществляется обычно при модульной разработке, в таком случае все события добавляются в базу данных (таблицаb_module_to_module
) - это необходимо сделать один раз (при добавлении модуля). Добавления обработчика событий - осуществляется в ходе выполнения программы и существует только в рамках исполняемого скрипта (закончили исполнение - забыли про событие).
Помимо способов подписки на события существуют типы событий: старого ядра и нового ядра. Обработчики событий старого ядра - принимают сколько угодно аргументов, передаваемых по значению или по ссылке и могут ожидать чего-угодно в результате своей работы. Например уже упомянутое событие OnBeforeCrmDealAdd модуля crm принимает массив полей добавляемого элемента по ссылке, а это значит что его можно изменить. Другой пример событие OnAfterCrmDealAdd, которое не обращает и не обрабатывает возвращаемый результат.
Обработчики событий нового ядра - принимают ровно один аргумент - наследник класса \Bitrix\Main\Event
и ожидают возврата \Bitrix\Main\EventResult
объекта (допустим null/void).
Для подписки на события необходимо получить инстанс класса EventManager
:
$eventManager = \Bitrix\Main\EventManager::getInstance();
И один из перечисленных методов подписки:
-
Сигнатура метода добавления обработчика событий нового ядра:
$eventManager->addEventHandler( $fromModuleId, $eventType, $callback, $includeFile = false, $sort = 100 ): int
Пояснения аргументов:
$fromModuleId
- идентификатор модуля-источника события$eventType
- событие на которое мы подписываемся$callback
- callable обработчик событий (или null, если обработка файлом)$includeFile
- false|string путь к файлу - обработчика (если указан$callback
- false)$sort
- порядок вызова (меньше - раньше)
В качестве возвращаемого значения методов добавления обработчика событий возвращается порядковый номер этой регистрации (см. ниже как отписаться от события).
-
Сигнатура метода добавления обработчика событий старого ядра отличается от нового ядра только названием метода:
addEventHandlerCompatible
Сигнатура метода регистрации обработчка событий нового ядра: -
Сигнатура метода регистрации обработчка событий нового ядра:
$registerEventHandler->registerEventHandler( $fromModuleId, $eventType, $toModuleId, $toClass = '', $toMethod = '', $sort = 100, $toPath = '', $toMethodArg = [] );
Пояснения аргументов:
$fromModuleId
- идентификатор модуля-источника события$eventType
- событие на которое мы подписываемся$toModuleId
- идентификатор модуля, который подписывается$toClass
- класс выполняющий обработку (для callback-обработчика, если файловый - пустая строка)$toMethod
- метод класса выполняющий обработку (для callback-обработчика, если файловый - пустая строка)$sort
- порядок вызова (меньше - раньше)$toPath
- относительный (относительно DOCUMENT_ROOT путь к файлу-обработку, для callback - пустая строка)$toMethodArg
- дополнительные аргументы передаваемые callback обработчик или доступные в$args
переменной файлового обработчика
- Сигнатура метода регистрации обработчика событий старого ядра отличается от нового ядра только названием метода:
registerEventHandlerCompatible
Например, если мы не разрабатываем модуль и хотим подписаться на событие OnAfterCrmDealAdd
модуля crm
, то у нас получиться следующий код:
$eventManager = \Bitrix\Main\EventManager::getInstance();
$eventManager->addEventHandlerCompatible(
'crm',
'OnAfterCrmDealAdd',
function( &$arFields )
{
// ...
}
);
Однако в соответствии с оговоренной ранее структурой папки local размещать код обработчика вместе с кодом подписки не следует во избежание раздувания файла с подписками. Наиболее практичный вариант в данном случае: разделение кода-обработчика и кода подписчика.
Например для нашей структуры папки local разделим указанный выше фрагмент.
В файле local/php_interface/events.php
:
$eventManager->addEventHandlerCompatible(
'crm',
'OnAfterCrmDealAdd',
[
"\\Vendor\\Subsystem\\Integration\\Crm\\DealCatcher",
"handleAfterDealAdd"
]
): void;
В файле local/php_interface/classes/Vendor/Subsystem/Integration/Crm/DealCatcher.php
:
namespace Vendor/Subsystem/Integration/Crm;
class DealCatcher
{
/**
* Handle crm::OnAfterCrmDealAdd event
* - do something with something
*
* @param array &$fields Some deal fields
* @return void
*/
public static function handleAfterDealAdd( array &$fields ): void
{
// ... Do what you need
}
}
Обратите внимание на следующие моменты:
- Поскольку мы использовали callback-обработчик мы явно обозначили метод
handleAfterDealAdd
статическим. - Комментарий к аргументу
$fields
-Some deal fields
- это именно некоторые поля которые было добавлены к сделке, а не все поля сделки. Событие не гарантирует что вам придет полный набор полей и вам всегда нужно проверять есть ли поле с кодом...
в$fields
. - Мы явно указали типы аргументов которые мы ждем.
Если мы этого не сделаем, то на php 8+ мы получим фатальную ошибку
should not be called statically in
Мы добавили php-doc комментарий к методу обработчику: указали какое событие он обрабатывает и что он делает
Комментрии
Комементариев нет, будьте первыми....