About bitrix-events
A skill for Bitrix developers that explains how to publish, register, and handle D7 and legacy events. It emphasizes matching handler signatures to the dispatcher and managing registration and results correctly.
Key features
- 01D7 event creation and dispatch
- 02Handler generation and registration
- 03D7 and legacy signature guidance
- 04Event results and cancellation
- 05Install and uninstall registration checks
Use cases
- 01Adding events to a Bitrix module
- 02Handling legacy user or page events
- 03Checking event handler signatures
- 04Reviewing persistent event registration
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ bxmaximum/ bitrix-framework-skills --skill bitrix-eventsAfter installing, type/bitrix-eventsin Claude Code to confirm it loaded.
Details
From the project READMEBitrix events
Baseline: main 23.0+ · Verified: main 26.800.0
Who dispatches decides the handler signature
| Dispatcher (find it in the caller) | Examples | Handler receives | Result |
|---|---|---|---|
new Event(...) + ->send() | own events, main:OnBeforeMailSend, ORM tablet events | VERSION 2 (registerEventHandler, addEventHandler): the Event object. VERSION 1 (*Compatible): ...array_values($params) | $event->getResults(); non-EventResult returns are wrapped as UNDEFINED |
GetModuleEvents() + ExecuteModuleEventEx() (legacy) | main:OnBeforeUserAdd, OnAfterUserAdd, OnPageStart, OnEpilog, iblock:OnBeforeIBlockElementAdd | raw args, whatever VERSION was registered — e.g. array &$arFields | caller-specific |
- Legacy
OnBefore*: cancel =$APPLICATION->ThrowException('…'); return false;(callers check=== false). Modify data through the reference&$arFields; a returned array (['FIELDS' => …]) is ignored. - ORM tablet / highload record events use
Bitrix\Main\ORM\EventManagerandORM\EventResult::modifyFields()— seebitrix-orm; HL event names —bitrix-highloadblock.
Publish a D7 event
php bitrix.php make:event PostCreated -m vendor.blog -C Post (Since main 25.900; older: write the class) → Vendor\Blog\Public\Event\Post\PostCreatedEvent (without -C: …\Public\Event\). The generated class passes no params — add them:
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)
{
parent::__construct('vendor.blog', 'PostCreated', ['postId' => $postId, 'authorId' => $authorId]);
}
}
$event = new PostCreatedEvent($post->getId(), $post->getAuthorId());
$event->send();
foreach ($event->getResults() as $result)
{
if ($result->getType() === \Bitrix\Main\EventResult::ERROR)
{
// caller decides: abort, log, collect errors
}
}
Cancel with a reason: return new EventResult(EventResult::ERROR, ['error' => new Error('…', 'CODE')]) — only callers that read it honor it (mail events: bitrix-mail).
Handle it
php bitrix.php make:eventhandler PostCreated --event-module=vendor.blog -m vendor.notify — name is the event name, -m is the handler module → Vendor\Notify\Internals\Integration\Vendor\Blog\EventHandler\PostCreatedEventHandler::handle(PostCreatedEvent $event). Add the missing use for the event class.
public static function handle(PostCreatedEvent $event): EventResult
{
$notifier = ServiceLocator::getInstance()->get(Notifier::class);
$result = $notifier->notifyAuthor($event->authorId);
return new EventResult($result->isSuccess() ? EventResult::SUCCESS : EventResult::ERROR, $result->getErrorMessages());
}
Handlers are static callbacks, never built by the container: resolve services inside (bitrix-framework).
Register
Persistent (module installer; unregister with the same args in DoUninstall):
EventManager::getInstance()->registerEventHandler(
fromModuleId: 'vendor.blog',
eventType: 'PostCreated',
toModuleId: 'vendor.notify',
toClass: PostCreatedEventHandler::class,
toMethod: 'handle',
);
registerEventHandlerCompatible()(same args, VERSION 1): a D7 event then passes...array_values($params)instead ofEvent. For legacyExecuteModuleEventExevents both calls deliver raw args; the kernel uses*Compatiblefor them by convention.- Since main 26.600*: declare handlers in
install/migrations/events.php(register()= VERSION 2,registerCompatible()= VERSION 1) —bitrix-modules. - Per request only:
addEventHandler($fromModuleId, $eventType, $callback, $includeFile = false, $sort = 100)(VERSION 2) /addEventHandlerCompatible()(VERSION 1), e.g. frominit.php. - Order: ascending
$sort(default 100) — 5th arg ofaddEventHandler, 6th ofregisterEventHandler. Event::send()runs every handler even after anERROR, but an exception thrown in a handler stops the chain and propagates to the caller.
Checklist
- Handler signature matches the dispatcher (
Eventvs raw&$arFields). - Every
registerEventHandlerhas anunRegisterEventHandlerwith identical args in uninstall. - Named args use kernel names (
fromModuleId, notfromModule). - Handlers catch and log their own exceptions; heavy work goes to Messenger (
bitrix-background-jobs). - Own events live in
lib/Public/Event/, handlers inlib/Internals/Integration/<Module>/EventHandler/.