Главная » Разработка Битрикс » События в Битрикс: AddEventHandler и все обработчики

События в Битрикс: AddEventHandler и все обработчики

Схема работы событий в Битрикс: ядро вызывает обработчик до операции, обработчик меняет данные или отменяет действие

События — механизм, позволяющий вмешаться в работу 1С-Битрикс, не трогая код ядра. Нужно проверять данные перед сохранением элемента, отправлять уведомление после создания заказа, дописывать поля пользователю при регистрации — всё это делается через обработчики событий.

Разберём, как устроен механизм, чем отличаются события «до» и «после», как отменить действие из обработчика и почему AddEventHandler постепенно уступает место подходу из D7.

Как это работает

В ключевых точках ядро вызывает все зарегистрированные обработчики события и передаёт им данные. Обработчик может их прочитать, изменить, а в некоторых случаях — прервать выполнение операции.

Регистрация обработчика выглядит так:

<?php // /local/php_interface/init.php

AddEventHandler(
    'main',              // модуль, который вызывает событие
    'OnBeforeUserAdd',   // имя события
    'myUserCheck'        // функция-обработчик
);

function myUserCheck(&$arFields)
{
    // ...
}

Регистрировать обработчики нужно в init.php — файле, который подключается на каждом хите до формирования страницы. Подробно он разобран в статье init.php в Битрикс.

Обработчик в классе

Функции в глобальной области быстро засоряют проект. Лучше использовать методы класса:

<?php

AddEventHandler('iblock', 'OnBeforeIBlockElementAdd', ['CatalogHandlers', 'onBeforeAdd']);

class CatalogHandlers
{
    public static function onBeforeAdd(&$arFields)
    {
        // ...
    }
}

События «до» и «после»

Большинство событий существует в двух вариантах, и разница между ними принципиальная.

OnBefore* OnAfter*
Когда срабатывает До выполнения операции После выполнения
Можно изменить данные Да, через ссылку Нет, операция завершена
Можно отменить Да Нет
Известен ID записи Нет при добавлении Да
Типичное применение Валидация, подстановка значений Уведомления, синхронизация

Отсюда простое правило: меняете данные — берите OnBefore, реагируете на факт — берите OnAfter. Попытка отправить письмо из OnBefore приведёт к тому, что письмо уйдёт даже если сохранение в итоге не состоится.

Нужна помощь с Битрикс?





    Изменение данных

    Чтобы правки в обработчике подействовали, параметр принимается по ссылке — через амперсанд. Без него функция получит копию, изменит её, и ничего не произойдёт:

    <?php
    
    AddEventHandler('iblock', 'OnBeforeIBlockElementAdd', 'setElementCode');
    
    function setElementCode(&$arFields)
    {
        // автоматически заполняем символьный код, если он пуст
        if (empty($arFields['CODE']) && !empty($arFields['NAME'])) {
            $arFields['CODE'] = CUtil::translit(
                $arFields['NAME'],
                'ru',
                ['replace_space' => '-', 'replace_other' => '-']
            );
        }
    }

    Забытый амперсанд — самая частая причина «обработчик срабатывает, но ничего не меняется». Ошибки при этом не возникает, что делает проблему особенно неприятной.

    Отмена операции

    Событие OnBefore* можно прервать. Механизм выглядит непривычно: нужно вернуть false и записать текст ошибки в глобальный объект приложения.

    <?php
    
    AddEventHandler('iblock', 'OnBeforeIBlockElementAdd', 'checkElementPrice');
    
    function checkElementPrice(&$arFields)
    {
        global $APPLICATION;
    
        if (isset($arFields['PROPERTY_VALUES']['PRICE'])
            && $arFields['PROPERTY_VALUES']['PRICE'] < 0) {
    
            $APPLICATION->throwException('Цена не может быть отрицательной');
            return false;
        }
    
        return true;
    }

    Без вызова throwException операция всё равно отменится, но пользователь увидит пустое сообщение об ошибке и не поймёт, что произошло.

    Часто используемые события

    МодульСобытиеКогда срабатывает
    mainOnBeforeUserAddПеред добавлением пользователя
    mainOnAfterUserRegisterПосле регистрации на сайте
    mainOnBeforeUserLoginПеред авторизацией
    mainOnBeforeEventAddПеред постановкой письма в очередь
    mainOnEpilogВ конце формирования страницы
    iblockOnBeforeIBlockElementAddПеред добавлением элемента
    iblockOnAfterIBlockElementUpdateПосле изменения элемента
    iblockOnBeforeIBlockElementDeleteПеред удалением элемента
    saleOnSaleOrderSavedПосле сохранения заказа
    catalogOnPriceAddПосле добавления цены

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

    Подход D7

    В новом ядре тот же механизм реализован через EventManager. Синтаксис отличается, возможностей больше:

    <?php
    
    use Bitrix\Main\EventManager;
    
    EventManager::getInstance()->addEventHandler(
        'iblock',
        'OnBeforeIBlockElementAdd',
        ['CatalogHandlers', 'onBeforeAdd']
    );

    Ключевые отличия от старого способа: обработчик можно снять, события своих модулей регистрируются штатно, а параметры передаются объектом Event вместо набора аргументов. Подробный разбор — в статье EventManager в Битрикс.

    Важный практический момент: старые события ядра остаются старыми. OnBeforeIBlockElementAdd вызывается в формате старого ядра независимо от того, каким способом вы его зарегистрировали. Регистрация через EventManager не меняет сигнатуру обработчика.

    Отладка обработчиков

    Обработчики выполняются в глубине ядра, где echo либо ничего не выводит, либо ломает страницу. Отлаживать нужно логом:

    <?php
    
    function myHandler(&$arFields)
    {
        \Bitrix\Main\Diag\Debug::writeToFile(
            $arFields,
            'OnBeforeIBlockElementAdd',
            '/local/logs/events.log'
        );
    }

    Порядок проверки, если обработчик не работает:

    1. Убедитесь, что init.php вообще подключается — запишите в лог факт подключения.
    2. Проверьте написание имени события: опечатка не вызывает ошибки.
    3. Проверьте, что модуль указан верно — iblock, а не main.
    4. Убедитесь, что параметр принимается по ссылке, если вы меняете данные.
    5. Проверьте, что метод класса объявлен как public static.

    Частые ошибки

    • Забыт амперсанд. Данные меняются в копии, оригинал остаётся прежним.
    • Тяжёлая логика в обработчике. Событие вроде OnAfterIBlockElementUpdate срабатывает при каждом сохранении, в том числе при массовом импорте — и импорт растягивается на часы.
    • Обработчик вызывает сам себя. Изменение элемента внутри обработчика события изменения элемента даёт бесконечную рекурсию. Нужен флаг-предохранитель.
    • Отправка письма из OnBefore. Уведомление уходит, даже если операция в итоге отменена.
    • Обработчики зарегистрированы в шаблоне сайта. В административной части они не подключатся, и поведение будет разным.
    • Отмена без throwException. Пользователь видит пустую ошибку и не понимает, что сделал не так.

    Итог

    События — штатный способ расширить поведение 1С-Битрикс без правок ядра. Обработчики регистрируются в init.php: AddEventHandler в старом стиле или EventManager в стиле D7.

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

    Нужна помощь с Битрикс?

    Исправим ошибку, доработаем сайт, ускорим Битрикс или поможем разобраться с проблемой.

    Услуги
    База знаний