bitrix-events

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Bitrix Events

Bitrix 事件

There are two event models: new (OOP,
Event
+
EventResult
) and old (string code + handler returning bool/array). For new code — use the new model. The old model is used for compatibility with the kernel (
OnBeforeUserAdd
,
OnPageStart
, ...).
Bitrix 包含两种事件模型:新模型(面向对象,
Event
+
EventResult
)和旧模型(字符串代码 + 返回布尔值/数组的handler)。新代码建议使用新模型,旧模型仅用于与内核兼容(如
OnBeforeUserAdd
OnPageStart
等)。

New Model — Publishing Your Event

新模型——发布自定义事件

1. Create Event Class

1. 创建事件类

bash
php bitrix/bitrix.php make:event PostCreated -m vendor.blog
Since main 25.900 for
make:*
. On older versions, scaffold the class manually.
File:
/local/modules/vendor.blog/lib/Public/Event/Post/PostCreatedEvent.php
.
php
<?php declare(strict_types=1);

namespace Vendor\Blog\Public\Event\Post;

use Bitrix\Main\Event;

final class PostCreatedEvent extends Event
{
    public function __construct(
        public readonly int $postId,
        public readonly int $authorId,
        public readonly string $title,
    ) {
        parent::__construct('vendor.blog', self::class, [
            'postId'   => $this->postId,
            'authorId' => $this->authorId,
            'title'    => $this->title,
        ]);
    }
}
bash
php bitrix/bitrix.php make:event PostCreated -m vendor.blog
make:*
命令从main 25.900版本开始支持。旧版本需要手动创建类。
文件路径:
/local/modules/vendor.blog/lib/Public/Event/Post/PostCreatedEvent.php
php
<?php declare(strict_types=1);

namespace Vendor\Blog\Public\Event\Post;

use Bitrix\Main\Event;

final class PostCreatedEvent extends Event
{
    public function __construct(
        public readonly int $postId,
        public readonly int $authorId,
        public readonly string $title,
    ) {
        parent::__construct('vendor.blog', self::class, [
            'postId'   => $this->postId,
            'authorId' => $this->authorId,
            'title'    => $this->title,
        ]);
    }
}

2. Dispatch Event from Service

2. 从服务中触发事件

php
use Vendor\Blog\Public\Event\Post\PostCreatedEvent;

$event = new PostCreatedEvent($post->getId(), $post->getAuthorId(), $post->getTitle());
$event->send();

foreach ($event->getResults() as $result)
{
    if ($result->getType() === \Bitrix\Main\EventResult::ERROR)
    {
        $this->logger->warning('Subscriber failed', ['errors' => $result->getParameters()]);
    }
}
php
use Vendor\Blog\Public\Event\Post\PostCreatedEvent;

$event = new PostCreatedEvent($post->getId(), $post->getAuthorId(), $post->getTitle());
$event->send();

foreach ($event->getResults() as $result)
{
    if ($result->getType() === \Bitrix\Main\EventResult::ERROR)
    {
        $this->logger->warning('Subscriber执行失败', ['errors' => $result->getParameters()]);
    }
}

3. Write Handler

3. 编写处理器

bash
php bitrix/bitrix.php make:eventhandler NotifyAuthor \
    --event-module=vendor.blog --handler-module=vendor.notify
EventManager invokes handlers via
call_user_func_array
(class + method). Handlers are not created by
ServiceLocator
— do not rely on constructor DI. Resolve services inside the handler method.
php
<?php declare(strict_types=1);

namespace Vendor\Notify\Internals\Integration\Blog\EventHandler;

use Bitrix\Main\DI\ServiceLocator;
use Bitrix\Main\Event;
use Bitrix\Main\EventResult;
use Vendor\Blog\Public\Event\Post\PostCreatedEvent;
use Vendor\Notify\Application\Service\Notifier;

final class NotifyAuthorHandler
{
    public static function handle(Event $event): EventResult
    {
        if (!$event instanceof PostCreatedEvent)
        {
            return new EventResult(EventResult::UNDEFINED);
        }

        /** @var Notifier $notifier */
        $notifier = ServiceLocator::getInstance()->get(Notifier::class);
        $result = $notifier->notifyAuthor($event->authorId, $event->title);

        return new EventResult(
            $result->isSuccess() ? EventResult::SUCCESS : EventResult::ERROR,
            $result->getErrorMessages(),
        );
    }
}
bash
php bitrix/bitrix.php make:eventhandler NotifyAuthor \
    --event-module=vendor.blog --handler-module=vendor.notify
EventManager 通过
call_user_func_array
(类+方法)调用处理器。处理器不会由
ServiceLocator
创建——不要依赖构造函数注入,需在处理器方法内部解析服务。
php
<?php declare(strict_types=1);

namespace Vendor\Notify\Internals\Integration\Blog\EventHandler;

use Bitrix\Main\DI\ServiceLocator;
use Bitrix\Main\Event;
use Bitrix\Main\EventResult;
use Vendor\Blog\Public\Event\Post\PostCreatedEvent;
use Vendor\Notify\Application\Service\Notifier;

final class NotifyAuthorHandler
{
    public static function handle(Event $event): EventResult
    {
        if (!$event instanceof PostCreatedEvent)
        {
            return new EventResult(EventResult::UNDEFINED);
        }

        /** @var Notifier $notifier */
        $notifier = ServiceLocator::getInstance()->get(Notifier::class);
        $result = $notifier->notifyAuthor($event->authorId, $event->title);

        return new EventResult(
            $result->isSuccess() ? EventResult::SUCCESS : EventResult::ERROR,
            $result->getErrorMessages(),
        );
    }
}

4. Register Handler in
install/index.php

4. 在
install/index.php
中注册处理器

php
\Bitrix\Main\EventManager::getInstance()->registerEventHandler(
    fromModule: 'vendor.blog',
    eventType: \Vendor\Blog\Public\Event\Post\PostCreatedEvent::class,
    toModuleId: 'vendor.notify',
    toClass: \Vendor\Notify\Internals\Integration\Blog\EventHandler\NotifyAuthorHandler::class,
    toMethod: 'handle',
);
In
DoUninstall()
mandatory
unRegisterEventHandler
with the same parameters.
php
\Bitrix\Main\EventManager::getInstance()->registerEventHandler(
    fromModule: 'vendor.blog',
    eventType: \Vendor\Blog\Public\Event\Post\PostCreatedEvent::class,
    toModuleId: 'vendor.notify',
    toClass: \Vendor\Notify\Internals\Integration\Blog\EventHandler\NotifyAuthorHandler::class,
    toMethod: 'handle',
);
DoUninstall()
方法中——必须使用相同参数调用
unRegisterEventHandler
来注销处理器。

Old Model (Compatibility)

旧模型(兼容模式)

Old events have string names:
OnBeforeUserAdd
,
OnAfterUserAdd
,
OnEpilog
,
OnPageStart
. They pass an array/object of parameters and return:
  • true
    /nothing — continue;
  • false
    +
    $APPLICATION->ThrowException(...)
    — cancel action;
  • array with
    'FIELDS' => [...]
    — modify fields (for
    OnBefore*
    ).
Registering handlers accepting the old signature:
php
EventManager::getInstance()->registerEventHandlerCompatible(
    'main',
    'OnAfterUserAdd',
    'vendor.blog',
    \Vendor\Blog\Internals\Integration\Main\EventHandler\OnAfterUserAddHandler::class,
    'handle',
);
The new
registerEventHandler
also works with old events but adapts them to the
Event $event
signature — parameters are retrieved via
$event->getParameter('fields')
, modification via
EventResult
.
旧事件使用字符串名称:
OnBeforeUserAdd
OnAfterUserAdd
OnEpilog
OnPageStart
。它们传递参数数组/对象,并返回以下结果:
  • true
    /无返回值——继续执行;
  • false
    +
    $APPLICATION->ThrowException(...)
    ——取消操作;
  • 包含
    'FIELDS' => [...]
    的数组——修改字段(适用于
    OnBefore*
    事件)。
注册支持旧签名的处理器:
php
EventManager::getInstance()->registerEventHandlerCompatible(
    'main',
    'OnAfterUserAdd',
    'vendor.blog',
    \Vendor\Blog\Internals\Integration\Main\EventHandler\OnAfterUserAddHandler::class,
    'handle',
);
新的
registerEventHandler
也可用于旧事件,但会将其适配为
Event $event
签名——参数需通过
$event->getParameter('fields')
获取,字段修改需通过
EventResult
实现。

Order and Chain of Handlers

处理器的执行顺序与调用链

  • Handlers run in ascending
    $sort
    order (default
    100
    ).
  • addEventHandler($fromModuleId, $eventType, $callback, $includeFile = false, $sort = 100)
    $sort
    is the 5th parameter.
  • registerEventHandler($fromModuleId, $eventType, $toModuleId, $toClass = '', $toMethod = '', $sort = 100, ...)
    $sort
    is the 6th parameter.
  • The new API (
    Event::send()
    ) collects results from all handlers — the chain is not interrupted even if one returns
    ERROR
    .
  • In the old API, a single
    false
    can interrupt the action (depends on the calling code in the kernel).
  • 处理器按
    $sort
    值升序执行(默认值为100)。
  • addEventHandler($fromModuleId, $eventType, $callback, $includeFile = false, $sort = 100)
    ——
    $sort
    是第5个参数。
  • registerEventHandler($fromModuleId, $eventType, $toModuleId, $toClass = '', $toMethod = '', $sort = 100, ...)
    ——
    $sort
    是第6个参数。
  • 新API(
    Event::send()
    )会收集所有处理器的结果——即使某个处理器返回
    ERROR
    ,调用链也不会中断。
  • 在旧API中,单个
    false
    返回值可能会中断操作(取决于内核中的调用代码)。

Dynamic Subscription in One Process

单进程内动态订阅

For hooks that don't need to be stored in the DB (tests, one-time wrappers):
php
EventManager::getInstance()->addEventHandler(
    'main',
    'OnAfterUserAdd',
    fn (array $fields) => /* ... */,
);
Such registration lives until the end of the request.
适用于无需存储到数据库的钩子(如测试、一次性包装器):
php
EventManager::getInstance()->addEventHandler(
    'main',
    'OnAfterUserAdd',
    fn (array $fields) => /* ... */,
);
此类注册仅在当前请求周期内有效。

Checklist

检查清单

  • Public event files — in
    /lib/Public/Event/<Aggregate>/
    .
  • Handlers of other modules' events — in
    /lib/Internals/Integration/<OtherModule>/EventHandler/
    .
  • Registration and unregistration of handlers as a pair in
    DoInstall
    /
    DoUninstall
    .
  • Custom events use
    Bitrix\Main\Event
    +
    EventResult
    instead of returning arrays.
  • Handler has no constructor DI — resolve services inside the method via
    ServiceLocator::get()
    .
  • Handler is idempotent and does not crash — wrap everything in
    try/catch
    with logging.
  • Heavy logic is moved to a queue (
    Messenger
    via
    $message->send()
    ), handler only dispatches a task.
  • 公共事件文件存放于
    /lib/Public/Event/<Aggregate>/
    目录。
  • 其他模块事件的处理器存放于
    /lib/Internals/Integration/<OtherModule>/EventHandler/
    目录。
  • 处理器的注册与注销需在
    DoInstall
    /
    DoUninstall
    中配对实现。
  • 自定义事件使用
    Bitrix\Main\Event
    +
    EventResult
    ,而非返回数组。
  • 处理器不依赖构造函数注入——需通过
    ServiceLocator::get()
    在方法内部解析服务。
  • 处理器需保证幂等性且不会崩溃——使用
    try/catch
    包裹逻辑并添加日志。
  • 重逻辑需转移到队列(通过
    $message->send()
    调用
    Messenger
    ),处理器仅负责分发任务。