Работа с событиями в D7

use Bitrix\Main;

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

Представьте пример, что у вас есть магазин, где в автоматическом режиме обновляются данные о ценах на основе данных получаемых из систем поставщиков. Но вы хотите чтобы вместо цен 123руб. 568руб. фигурировали округленные цены 120руб. и 570руб. Для этого мы подписываемся на событие изменения цены и округляем её.
Или же при оформлении заказа мы хотите получать уведомление в Telegram, для этого вам необходимо подписаться на событие создание заказа и отправить его.

Тут мы рассмотрим систему событий ядра d7.

Менеджер событий

Main\EventManager::getInstance() Это центральный объект системы событий, содержит в себе все данные по обработчикам событий. Когда событие вызывается, он как раз и запускает все обработчики.

Обработка событий

Чтобы получить уведомление о том или ином событии, на него нужно подписаться. Сделать это можно следующим образом:

/**
 * Функция
 */
Main\EventManager::getInstance()->addEventHandler(
    'module',
    'eventName',
    'functionName'
);

/**
 * Класс - метод
 */
Main\EventManager::getInstance()->addEventHandler(
    'module',
    'eventName',
    ['className', 'methodName']
);

Метод addEventHandler() имеет до пяти аргументов:

  1. Название модуля, порождающее событие;
  2. Название самого события;
  3. Вызываемый код, который может быть использован call_user_func_array();
  4. Подключаемый файл, будет дополнительно подключен (опционально);
  5. Сортировка, порядок выполнения слушателей, по умолчанию 100 (опционально).

Когда обработчик зарегистрирован, он ждет пока сработает событие. При срабатывании события, вызывается функция из третьего параметра, с одним единственным аргументом в виде объекта Main\Event. Пример реализации обработки событий в ядре d7


class className
{
    public static function methodName(Main\Event $event)
    {
        /**
         * Все переданные параметры
         */
        $arParams = $event->getParameters();

        /**
         * Конкретный параметр
         */
        $arFields = $event->getParameter('fields');

        $result = new Main\Entity\EventResult();

        /**
         * Изменение данных
         */
        $result->modifyFields(
            [
                'secondVar' => 'N',
                'newVar' => 'val',
            ]
        );

        /**
         * Удаление данных
         */
        $result->unsetField('firstVar');

        /**
         * Ошибка
         */
        if (666 === $arParams['userId']) {
            $result->addError(new Main\Entity\EntityError('user is banned', 'ERROR_USER_IS_BAN'));
        }

        return $result;
    }
}

Создание и запуск событий

В D7, по сравнению со старым ядром, снижены требования к данным, которые должен иметь код, порождающий событие. Пример отправки события:

/**
 * Без параметров
 */
$event = new Main\Event('module', 'eventName');
$event->send();

/**
 * С параметрами
 */
$fields = [
    'firstVar' => 'value',
    'secondVar' => 'Y',
];
$event = new Main\Event(
    'module',
    'eventName',
    [
        'fields' => &$fields,
        'user' => 123,
    ]
);
$event->send();

Конструктор Main\Event имеет до четырех аргументов:

  1. Название модуля;
  2. Название самого события;
  3. Параметры, передаваемые в событие (опционально) [массив];
  4. Фильтр с названием модулей (опционально) [массив].

Фильтр, это массив с названием модулей, слушатели которых будут выполнены. Актуально только для зарегистрированных обработчиком модуль — модуль Main\EventManager::getInstance()->registerEventHandler();.

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

Результатом обработки события будет экземпляр класса Main\EventResult.

У Main\EventResult есть наследник Main\Entity\EventResult который позволяет модифицировать результат.

Обратите внимание, что параметры можно передавать по ссылке &$fields, и модифицировать напрямую в обработке.

foreach ($event->getResults() as $eventResult) {
    switch ($eventResult->getType()) {
        case Main\EventResult::ERROR:
            /**
             * Обработка ошибки
             */
            $handlerRes = $eventResult->getParameters();

            if ($eventResult instanceof Main\Entity\EventResult) {
                /**
                 * Появляется массив с ошибками
                 */
                $arErrors = $eventResult->getErrors();
            }

            break;
        case Main\EventResult::SUCCESS:
            /**
             * Успешно
             */
            $handlerRes = $eventResult->getParameters();

            if ($eventResult instanceof Main\Entity\EventResult) {
                /**
                 * Появляется возможность модифицировать результат
                 */
                foreach ($eventResult->getUnset() as $val) {
                    unset($fields[$val]);
                }

                $modified = $eventResult->getModified();
                if (!empty($modified)) {
                    $fields = array_merge($fields, $modified);
                }
            }

            break;
        case Main\EventResult::UNDEFINED:
            /**
             * Обработчик вернул неизвестно что вместо объекта класса Main\EventResult
             * его результат по прежнему доступен через getParameters
             */
            $handlerRes = $eventResult->getParameters();

            break;
    }
}