События
Событие — это действие или изменение состояния системы, например, нажатие кнопки пользователем или завершение загрузки данных. События уведомляют части приложения об изменениях, что позволяет системе реагировать на них.
Базовое использование
Чтобы создать и отправить событие, используйте класс Bitrix\Main\Event и его метод send.
Пример отправки события:
$event = new \Bitrix\Main\Event('my.helpdesk', 'TicketClosed');
$event->send();
Пример обработчика для этого события:
class TicketClosedEventHandler
{
public static function handle(\Bitrix\Main\Event $event)
{
// Код для обработки события
}
}
Если нужно передать дополнительные параметры, укажите их третьим аргументом:
$event = new \Bitrix\Main\Event('my.helpdesk', 'TicketClosed', [
'ticketId' => 123,
'closeReason' => '...',
]);
$event->send();
Чтобы обработчик получил данные, используйте методы getParameter и getParameters:
class TicketClosedEventHandler
{
public static function handle(\Bitrix\Main\Event $event)
{
// Получить один параметр
$ticketId = $event->getParameter('ticketId');
// Получить все параметры
$params = $event->getParameters();
$ticketId = $params['ticketId'];
// Обработка события
}
}
Консольные команды
Bitrix Framework предоставляет CLI-команды для удобной работы с событиями.
Создание события
Чтобы создать событие, используйте команду make:event.
Пример создания события:
php bitrix.php make:event TicketClosed -m my.helpdesk —no-interaction
Эта команда создаст файл /local/modules/my.helpdesk/lib/Public/Event/TicketClosedEvent.php:
namespace My\Helpdesk\Public\Event;
use Bitrix\Main\Event;
final class TicketClosedEvent extends Event
{
public function __construct(
public readonly int $ticketId,
public readonly ?string $closeReason,
)
{
parent::__construct(
'my.helpdesk',
'TicketClosed',
);
}
}
Теперь для отправки события можно использовать созданный класс, а не базовый:
$event = new TicketClosedEvent(
ticketId: 123,
closeReason: '...',
);
$event->send();
Данные передаются как свойства события, а не через массив параметров. Это облегчает работу с данными.
Создание обработчика
Чтобы создать обработчик, используйте команду make:eventhandler.
Пример создания обработчика:
php bitrix.php make:eventhandler TicketClosed —event-module my.helpdesk —handler-module my.helpdesk —no-interaction
Эта команда создаст файл local/modules/my.helpdesk/lib/Internals/Integration/My/Helpdesk/EventHandler/TicketClosedEventHandler.php:
namespace My\Helpdesk\Internals\Integration\My\Helpdesk\EventHandler;
use Bitrix\Main\EventResult;
final class TicketClosedEventHandler
{
public static function handle(TicketClosedEvent $event): EventResult
{
# process
return new EventResult(EventResult::SUCCESS);
}
}
В сгенерированном коде нет полного пути к классу события. Нужно указать его в аргументах метода handle или использовать конструкцию use.
Теперь свойства события можно использовать внутри обработчика:
namespace My\Helpdesk\Internals\Integration\My\Helpdesk\EventHandler;
use Bitrix\Main\EventResult;
use My\Helpdesk\Public\Event\TicketClosedEvent;
final class TicketClosedEventHandler
{
public static function handle(TicketClosedEvent $event): EventResult
{
$ticketId = $event->ticketId;
$closeReason = $event->closeReason;
// Обработка события
return new EventResult(EventResult::SUCCESS);
}
}
Результаты событий
Обработчик события может возвращать результат. Это необязательно — можно вернуть null или ничего для методов с типом void. Если обработчик должен повлиять на дальнейшую логику выполнения, например, запретить операцию или передать дополнительные параметры, используйте Bitrix\Main\EventResult.
В качестве примера рассмотрим событие BeforeTicketCloseEvent. Оно вызывается перед закрытием тикета и позволяет обработчикам проверить, можно ли выполнить операцию. Если любой из обработчиков вернет ошибку, процесс закрытия прервется.
final class BeforeTicketCloseEvent extends Event
{
public function __construct(
public readonly int $ticketId,
public readonly ?string $closeReason,
)
{
parent::__construct(
'my.helpdesk',
'BeforeTicketClose',
);
}
}
Проверка перед закрытием тикета:
use Bitrix\Main\Error;
use Bitrix\Main\EventResult;
use Bitrix\Main\Result;
final class TicketService
{
public function close(int $ticketId, string $closeReason): Result
{
$result = new Result();
$error = $this->canClose($ticketId, $closeReason);
if ($error)
{
return $result->addError($error);
}
// Код для закрытия тикета
return $result;
}
private function canClose(int $ticketId, string $closeReason): Error
{
$event = new BeforeTicketCloseEvent($ticketId, $closeReason);
$event->send();
foreach ($event->getResults() as $result)
{
if ($result->getType() === EventResult::ERROR)
{
return new Error(
(string)($result->getParameters()['message'] ?? 'Unknown'),
);
}
elseif ($result->getType() === EventResult::SUCCESS)
{
// Обработка успешного результата
}
elseif ($result->getType() === EventResult::UNDEFINED)
{
// Обработка неопределенного результата
}
}
return null;
}
}
Пример обработчика, который возвращает ошибку:
final class BeforeTicketCloseEventHandler
{
public static function handle(BeforeTicketCloseEvent $event): EventResult
{
if (self::hasOpenTasks($event->ticketId))
{
return new EventResult(
EventResult::ERROR,
parameters: [
'message' => \Bitrix\Main\Localization\Loc::getMessage('TICKET_HAS_OPEN_TASKS'),
],
moduleId: 'my.taskTracker',
);
}
return new EventResult(EventResult::SUCCESS);
}
}
Регистрация обработчиков
Чтобы обработчики BeforeTicketCloseEventHandler и TicketClosedEventHandler начали работать, их нужно зарегистрировать. Используйте для этого объект Bitrix\Main\EventManager и его метод registerEventHandler:
\Bitrix\Main\EventManager::getInstance()->registerEventHandler(
fromModule: 'my.helpdesk',
eventType: 'BeforeTicketClose',
toModuleId: 'my.helpdesk',
toClass: My\Helpdesk\Internals\Integration\My\Helpdesk\EventHandler\TicketClosedEventHandler::class,
toMethod: 'handle',
);
Регистрируйте обработчики один раз при установке модуля. Они хранятся в базе данных.
При удалении модуля удаляйте обработчики с помощью метода unRegisterEventHandler:
\Bitrix\Main\EventManager::getInstance()->unRegisterEventHandler(
fromModule: 'my.helpdesk',
eventType: 'BeforeTicketClose',
toModuleId: 'my.helpdesk',
toClass: My\Helpdesk\Internals\Integration\My\Helpdesk\EventHandler\TicketClosedEventHandler::class,
toMethod: 'handle',
);
Есть также способ добавить обработчик динамически через метод addEventHandler:
\Bitrix\Main\EventManager::getInstance()->addEventHandler(
fromModule: 'my.helpdesk',
eventType: 'BeforeTicketClose',
callback: '\My\Helpdesk\Internals\Integration\My\Helpdesk\EventHandler\TicketClosedEventHandler::handle',
);
Не рекомендуется использовать динамическую регистрацию. Она усложняет отладку и анализ системы. Постоянная регистрация в одном месте позволяет легко найти все обработчики событий.
Старые события и режим совместимости
В продукте есть события в старом формате, например OnBeforeUserAdd. У них нет объекта Bitrix\Main\Event, и в обработчик передается произвольный набор аргументов.
Пример обработчика для старого события:
class OnBeforeUserAddEventHandler
{
public static function handle(array &$fields): mixed
{
// Обработка события
// Результат зависит от конкретного события
return true;
}
}
Для регистрации используйте метод registerEventHandlerCompatible:
\Bitrix\Main\EventManager::getInstance()->registerEventHandlerCompatible(
fromModule: 'main',
eventType: 'OnBeforeUserAdd',
toModuleId: 'my.testing',
toClass: My\Testing\Internals\Integration\Main\EventHandler\OnBeforeUserAddEventHandler::class,
toMethod: 'handle',
);
Для работы со старыми событиями используются функции:
-
GetModuleEvents -
AddEventHandler -
ExecuteModuleEvent -
ExecuteModuleEventEx
Если вы видите эти функции в коде, обрабатывайте события в режиме совместимости.