d7-events
Skill4 starsChanged 4 months agoMITView on GitHub
Register and handle 1C-Bitrix events with the D7 EventManager — addEventHandler, sending and handling Event objects, module vs global events, handler priority (sort), and D7-to-legacy event compatibility. Use when the user needs to control the order in which handlers run for an event — setting the sort/priority argument so one handler runs before or after another; the user is declaring a module's event handlers — registering them from the module's `include.php`/installer, or hooking events of another module such as `main:OnBeforeUserAdd` or `sale:OnSaleOrderSaved`; the user needs to register an event handler — `EventManager::addEventHandler()` (D7) or the legacy `AddEventHandler()` — to react to a module or system event; the user is firing a custom event so other code can hook in — constructing an `\Bitrix\Main\Event` and calling `$event->send()`, or reading results back from its handlers. Keywords: bitrix, events, eventmanager, addeventhandler, handler, priority, sort, module-events, d7, legacy, битрикс,…
In this repository119 other files it gives its agents.
- strategy-bitrix-d7-incrementalSkill
- strategy-explicit-over-magicSkill
- strategy-framework-conventionsSkill
- strategy-legacy-safe-editsSkill
- strategy-minimal-diffSkill
- strategy-no-untested-refactorSkill
- strategy-preserve-public-apiSkill
- strategy-readonly-immutabilitySkill
- strategy-security-firstSkill
- strategy-test-drivenSkill
- openapiSkill
- paginationSkill
- rest-designSkill
- versioningSkill
- cqrsSkill
- dependency-inversionSkill
- hexagonalSkill
- repository-patternSkill
- service-layerSkill
- bitrixSkill
- findings-reportSkill
- laravelSkill
- performanceSkill
- phpSkill
- project-analysisSkill
- refactoringSkill
- roi-prioritizationSkill
- securitySkill
- stack-detectionSkill
- cache-layersSkill
- component-engineSkill
- d7-loaderSkill
- d7-orm-queriesSkill
- iblock-elementsSkill
- kernel-main-moduleSkill
- localizationSkill
- controllersSkill
- ormSkill
- validationSkill
- controllersSkill
- query-builderSkill
- routingSkill
- autoload-psr4Skill
- dependency-managementSkill
- scriptsSkill
- connection-poolingSkill
- mysql-indexingSkill
- redisSkill
- transactionsSkill
- ci-github-actionsSkill
- deployment-strategiesSkill
- docker-phpSkill
- env-configSkill
- associationsSkill
- entities-mappingSkill
- orm-basicsSkill
- entity-apiSkill
- module-developmentSkill
- routing-controllersSkill
- formsSkill
- The first 60 shown.
The file
We split this skill into the rules it gives an agent
9 rules. About 0 are common, 6 are distinctive, and 3 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈6
Distinctive · estimate
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 89
Do not use this skill for scheduled background work (Bitrix agents, cron).
- Very specific: line 91
Do not use this skill for a non-Bitrix event system (Symfony EventDispatcher, Laravel events, PSR-14).
- Very specific: line 133
Put the handler in an autoloadable class with a static method, e.g.
- Distinctive: line 135
Verify: The handler class autoloads and its static method is callable.
- Distinctive: line 138
Verify: A fresh request fires the handler without any page-level registration.
- Distinctive: line 141
Verify: Invalid input is rejected and a veto returns EventResult::ERROR, not an exception.
- Distinctive: line 157
Verify: Handlers registered for that module and event id are invoked.
- Distinctive: line 160
Verify: A handler returning EventResult::ERROR halts the caller's action.
- Very specific: line 173
When your handler must run before or after another for the same event, pass an explicit sort value to addEventHandler.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
<!-- generated: do not edit — source: knowledge/atoms/bitrix/d7-events/ --><!-- schema: atomVersion=3 skillVersion=2 graphVersion=1 --><!-- compile: @php-skills/compiler v1.0.0 (deterministic build) -->Bitrix D7 Events
When to use
- The user needs to control the order in which handlers run for an event — setting the sort/priority argument so one handler runs before or after another.
- The user is declaring a module's event handlers — registering them from the
module's
include.php/installer, or hooking events of another module such asmain:OnBeforeUserAddorsale:OnSaleOrderSaved. - The user needs to register an event handler —
EventManager::addEventHandler()(D7) or the legacyAddEventHandler()— to react to a module or system event. - The user is firing a custom event so other code can hook in — constructing an
\Bitrix\Main\Eventand calling$event->send(), or reading results back from its handlers.
When NOT to use
- Do not use this skill for scheduled background work (Bitrix agents, cron); those run on a timer, whereas events fire in response to an action.
- Do not use this skill for a non-Bitrix event system (Symfony EventDispatcher,
Laravel events, PSR-14); the
\Bitrix\Main\EventManager/EventAPI is Bitrix-specific.
Core guidance
- Prefer the D7 EventManager for new handlers — In new code register handlers through
\Bitrix\Main\EventManager::getInstance()->addEventHandler()rather than the legacyAddEventHandler(); keep the legacy call only when patching legacy code.
Decision Engine
Walk this section before choosing an implementation path.
Are you registering a new handler, or editing an existing legacy AddEventHandler call?
├── Editing legacy handler: → legacy — keep the existing AddEventHandler call and make a minimal local edit; do not rewrite it to EventManager opportunistically.
└── New handler: Is this a handler that belongs to a module and should fire on every request it is active for?
├── Module-scoped handler: → eventmanager-include — register via EventManager in the module include.php, pointing at a static handler method with an explicit sort.
└── Ad hoc handler: → eventmanager-runtime — call addEventHandler at runtime for this request only when the hook is genuinely one-off and not module-wide.
Full engine: references/decision-engine.md — Decision Tree, Priority Matrix, Decision Table.
Workflows
Workflow: Register Module Handler
Progress:
- [ ] Put the handler in an autoloadable class with a static method, e.g
- [ ] In the module `include.php` call
`EventManager::getInstance()->addEventHandler('iblock', 'OnAfterIBlockElementUpdate', [Handler::class, 'onIblockElementUpdate'], false, $sort)`
- [ ] Inside the handler, read `$event->getParameter('...')`, validate and cast it, do
minimal work, and return an `EventResult` when you need to veto or extend the action- Put the handler in an autoloadable class with a static method, e.g.
Vendor\Module\EventHandlers::onIblockElementUpdate(\Bitrix\Main\Event $event).- Verify: The handler class autoloads and its static method is callable.
- In the module
include.phpcallEventManager::getInstance()->addEventHandler('iblock', 'OnAfterIBlockElementUpdate', [Handler::class, 'onIblockElementUpdate'], false, $sort).- Verify: A fresh request fires the handler without any page-level registration.
- Inside the handler, read
$event->getParameter('...'), validate and cast it, do minimal work, and return anEventResultwhen you need to veto or extend the action.- Verify: Invalid input is rejected and a veto returns EventResult::ERROR, not an exception.
Workflow: Send Custom Event
Progress:
- [ ] Build the event with
`$event = new \Bitrix\Main\Event('vendor.module', 'OnSomethingHappened', $params);`
and call `$event->send();` at the extension point
- [ ] Iterate `$event->getResults()` and, if any `EventResult` has type
`EventResult::ERROR`, treat the action as vetoed and stop- Build the event with
$event = new \Bitrix\Main\Event('vendor.module', 'OnSomethingHappened', $params);and call$event->send();at the extension point.- Verify: Handlers registered for that module and event id are invoked.
- Iterate
$event->getResults()and, if anyEventResulthas typeEventResult::ERROR, treat the action as vetoed and stop.- Verify: A handler returning EventResult::ERROR halts the caller's action.
Best practices
- Handlers for D7 events sent via
Event::send()receive oneEventobject; some legacy/core events are still raised the old way and pass positional arguments — write the handler signature to match how that specific event is fired - Register a module's event handlers in its
include.php(loaded whenever the module is included), pointing at a static handler class method, instead of callingaddEventHandlerfrom page or component code - To veto or alter an action from a D7 handler, return an
\Bitrix\Main\EventResultwith the appropriate type (for exampleEventResult::ERROR), rather than throwing an exception from the handler - When your handler must run before or after another for the same event, pass an
explicit
sortvalue toaddEventHandler; lower sort runs first, and the default (100) leaves order undefined relative to other defaults - Register handlers as a
[Namespace\\Class::class, 'onEvent']static callable, not an inline closure, so the handler is autoloadable and does not run its class body until the event fires
Anti-patterns
| Anti-pattern | Why it fails | Do instead |
| Registering a closure handler from include.php | A closure defined in include.php loads its whole enclosing scope eagerly, cannot<br>be autoloaded on demand, and is harder to test or unregister. | Move the handler into an autoloadable handler class and register<br>[Handler::class, 'onEvent']. |
| Doing heavy or blocking work inside a handler | The handler runs inline with the action that raised the event, so slow work<br>blocks the user request and can time out or partially apply. | Do minimal work in the handler and offload heavy processing to an agent, a queue,<br>or a background job. |
| Throwing an exception to cancel an action | The event system expects an EventResult to decide whether to continue; an<br>uncaught throw escapes it and destabilises the whole dispatch. | Return an \Bitrix\Main\EventResult with the appropriate type (for example<br>EventResult::ERROR) to veto the action cleanly. |
See references/anti-patterns.md.
Debugging
- Duplicate registration makes a handler run twice — Each addEventHandler call adds another entry; the event system does not deduplicate. Fix: Register each handler in exactly one place — the module
include.php— and remove any redundant page-level or installer registrations. - Handler never fires because registration ran too late — addEventHandler only affects events sent after registration, not ones already dispatched. Fix: Register the handler early, from the module's
include.php, so it is in place before the event is raised. - Wrong handler signature for a D7 vs legacy event — D7 events pass one Event object while legacy events pass positional arguments. Fix: Check how the specific event is fired and match the signature — accept a single
\Bitrix\Main\Eventfor D7 events, positional parameters for legacy ones.
Production checklist
- The module that raises the event you hook is included with a checked
Loader::includeModulebefore registering the handler, so the event actually fires. - Every module-wide handler is registered from the module's
include.phpvia the EventManager, not from page, template, or component code. - Each handler's signature matches the calling convention of the event it hooks —
a single
Eventobject for D7 events, positional arguments for legacy events. - When more than one handler listens to an event and order matters, each passes an
explicit
sortvalue rather than depending on registration order. - Each handler is a
[Class::class, 'method']static callable whose class is autoloadable, not an inline closure or a call into unloaded code. - Values read from an event's parameters are validated and cast before being used in queries, filesystem paths, or other side effects, since they may originate from user input.
Version notes
- The D7 EventManager supersedes AddEventHandler —
\Bitrix\Main\EventManagerwithEvent/EventResultobjects is the current D7 event API; the legacyAddEventHandler()/ExecuteModuleEventEx()functions remain as a compatibility layer, and many core events are still raised the legacy way.
Security
- Treat event parameters as untrusted input — Data carried in an event's parameters can originate from user input (a submitted form, an API body, an edited element); validate and cast it inside the handler before using it in SQL, filesystem paths, or other side effects.
Testing
- Activation and decision behavior are verified in
eval/scenarios/bitrix/d7-events.yaml.
Additional resources
- references/anti-patterns.md
- references/core.md
- references/decision-engine.md
- references/examples.md
- references/pitfalls.md
- references/recipes.md
- references/version-differences.md
Knowledge graph
Prerequisites: bitrix/kernel-main-module
Related: ai-rules/strategy-bitrix-d7-incremental, bitrix/d7-loader
Behavior constraints: ai-rules/strategy-legacy-safe-edits
<!-- graph-fragment: graph/fragments/bitrix/d7-events.yaml -->Skill contract
Produces: events.d7-handler-registered
Requires: bitrix.module-loaded
Risk: medium · Confidence: 0.9
<!-- contract-fragment: contracts/fragments/bitrix/d7-events.yaml -->Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

