1С Битрикс · 6 мин чтения

Обработчики событий Битрикс: своя логика без правки ядра

Обработчики событий Битрикс - единственный вменяемый способ добавить свою логику поверх стандартного функционала модулей так, чтобы она не слетела при следующем обновлении. Раз в несколько месяцев ко мне приходит проект, где предыдущий разработчик правил файлы прямо внутри /bitrix/modules/sale/ или /bitrix/modules/iblock/, и после обновления модуля все эти правки откатываются молча, без предупреждений. Дальше - как выстроить логику на обработчиках событий так, чтобы она пережила и обновление ядра, и смену подрядчика.

Почему обработчик события лучше правки файлов модуля

Ядро Битрикс и большинство модулей построены на событийной модели: перед или после ключевого действия (сохранение заказа, добавление пользователя, изменение элемента инфоблока) система генерирует событие, а сторонний код может на него подписаться через EventManager. Это тот же принцип, что action и filter хуки в WooCommerce - только терминология своя и механизм чуть более низкоуровневый.

Правка файла модуля работает ровно до первого обновления через маркетплейс или Update Center. Обновление перезаписывает файлы модуля целиком, и все точечные правки исчезают без резервной копии где-либо в интерфейсе. Я видел, как интеграция с эквайрингом, вписанная прямо в order.php, пропадала после планового обновления модуля sale - магазин двое суток принимал заказы без проведения оплаты.

Критерий Правка файла модуля Обработчик события
Переживает обновление модуля Нет Да
Виден в списке кастомизаций Нет Да, через init.php или локальный модуль
Откатывается одной командой Сложно, нужен диф Да, комментируем строку регистрации
Годится для нескольких независимых доработок Конфликтуют между собой Каждая - отдельный хендлер

Где регистрировать обработчики: init.php, локальный модуль, класс события

Самый быстрый вариант - /local/php_interface/init.php. Файл подключается на каждом хите до инициализации компонентов, туда пишут AddEventHandler и не думают о жизненном цикле модулей. Для маленького интернет-магазина или лендинга на Битрикс этого достаточно.

<?php
use BitrixMainEventManager;

EventManager::getInstance()->addEventHandler(
    'sale',
    'OnSaleOrderSaved',
    ['MyCompanyOrderHandlers', 'onOrderSaved']
);
?>

Когда доработок больше пяти-шести и они относятся к разным модулям (sale, iblock, main, catalog), init.php превращается в свалку. В таких проектах я выношу обработчики в локальный модуль (/local/modules/mycompany.events/), регистрирую их через install/index.php методом RegisterModuleDependences и получаю нормальный жизненный цикл: установка, удаление, версионирование через .settings.php. Для интеграций с CRM, эквайрингом или СДЭК это оправдано почти всегда - код живёт отдельно от темплейта и не потеряется при смене визуальной темы сайта.

Как найти нужное событие в чужом проекте

Большая часть времени на доработке чужого Битрикса уходит не на написание кода, а на поиск правильного события. Три рабочих способа:

  • Включить bitrix_event_log в dbconn.php (define(‘BX_COMP_MANAGED_CACHE’, true) плюс отладочный логгер) и посмотреть, какие события реально стреляют на нужном действии.
  • grep по /bitrix/modules/*/lib и /bitrix/modules/*/classes на вызовы GetEvent или events()->send() - так находятся события, которых нет в официальной документации.
  • Держать под рукой шпаргалку самых ходовых событий: OnSaleOrderSaved и OnSaleOrderPaid для заказов, OnAfterUserAdd и OnAfterUserUpdate для пользователей, OnAfterIBlockElementUpdate для инфоблоков, OnPageStart для логики на каждый хит.

На практике связка «нашёл событие через grep - проверил через var_export в лог» экономит часы по сравнению с попыткой угадать сигнатуру по устаревшей документации.

Бесплатный материал

🎁 Полезный скрипт в подарок

Подпишитесь на Telegram - пришлю готовый скрипт по этой теме.

Без спама. Отписка в 1 клик.

Пример из практики: уведомление в Telegram при оплате заказа

Заказчику с интернет-магазином на Битрикс и эквайрингом от Т‑Банка нужно было получать уведомление в Telegram, как только заказ переходит в статус оплаченного - менеджеры физически не успевали проверять админку каждые пять минут. Решение - обработчик на OnSaleOrderPaid, который дергает Telegram Bot API напрямую.

<?php
AddEventHandler('sale', 'OnSaleOrderPaid', 'notifyTelegramOnPaid');

function notifyTelegramOnPaid(BitrixSaleOrder $order)
{
    if (!$order->isPaid()) {
        return;
    }

    $text = 'Оплачен заказ №' . $order->getId() . ' на сумму ' . $order->getPrice() . ' руб.';

    file_get_contents(
        'https://api.telegram.org/bot' . TG_BOT_TOKEN . '/sendMessage?chat_id='
        . TG_CHAT_ID . '&text=' . urlencode($text)
    );
}
?>

Если у команды уже есть бот на aiogram для внутренних уведомлений, проще слать не прямой запрос к Bot API, а вебхук на эндпоинт этого бота - тогда вся логика форматирования сообщений и рассылки по нескольким чатам остаётся на стороне Python-приложения, а обработчик в Битриксе занимается только тем, что умеет: следит за событием и передаёт данные заказа.

Интеграция с СДЭК через события заказа

Типичная задача для интернет-магазина: при сохранении заказа с доставкой СДЭК автоматически создавать заявку в личном кабинете службы через их API, а не руками переносить адрес и вес посылки. Логика вешается на OnSaleOrderSaved, проверяет способ доставки по коду службы и делает запрос к СДЭК только для новых заказов, чтобы не дублировать заявку при каждом редактировании в админке.

Для команд без своего разработчика тот же сценарий можно собрать в n8n: вебхук из Битрикса по событию заказа прилетает в workflow, который сам обращается к API СДЭК и пишет трек-номер обратно через REST. Это медленнее по отклику, чем прямой PHP-обработчик, но избавляет от необходимости деплоить код на боевой сервер при каждом изменении логики.

Простая доработка существующего обработчика - правка условия, добавление проверки статуса - занимает у меня час-полтора. Полноценная интеграция с внешним API вроде СДЭК или банковского эквайринга, с обработкой ошибок и повторными попытками при таймауте, - это отдельный проект, и по сложности он сопоставим с комплексной интеграцией на других платформах: разработку такой интеграции под ключ можно заказать вместо самостоятельной сборки по обрывкам документации.

Приоритеты выполнения и типичные ошибки

На одно событие может быть подписано сразу несколько обработчиков - от ядра, от модулей маркетплейса и от самописного кода. Порядок вызова задаётся параметром sort в AddEventHandler (по умолчанию 100): чем меньше число, тем раньше сработает обработчик. Если логика зависит от результата другого хендлера, порядок нужно проверять явно, а не полагаться на очередность подключения файлов.

Самая частая ошибка - необработанное исключение внутри обработчика. Если хендлер на OnSaleOrderSaved падает с фатальной ошибкой, обрывается вся цепочка событий после него, и заказ может сохраниться в системе, но остаться без оповещения бухгалтерии или без создания заявки в службе доставки. Любой внешний запрос внутри обработчика - к API банка, СДЭК или Telegram - обязан быть обёрнут в try/catch с логированием через AddMessage2Log, иначе разовый сетевой сбой у стороннего сервиса роняет обработку заказов целиком.

Вторая по частоте проблема - кеширование результата события через managed cache без сброса тега при изменении данных внутри самого обработчика. Хендлер меняет свойство элемента инфоблока, но не сбрасывает тег кеша - и на витрине показываются старые данные ещё несколько часов, пока кеш не истечёт по TTL.

Когда обработчиков событий недостаточно

События хорошо ложатся на реактивную логику: что-то произошло - выполнить действие. Для задач по расписанию (ежедневная выгрузка остатков, синхронизация цен раз в час) нужны агенты - они регистрируются похожим образом, но выполняются по cron, а не в ответ на действие пользователя. Для взаимодействия с внешними системами по REST есть отдельная группа событий OnRestServiceBuildDescription - если Битрикс выступает не источником, а получателем интеграции.

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

Чтобы сайт работал без сбоев

Техподдержка

от 15 000 ₽/мес

Подробнее →

Частые вопросы

Обработчик события Битрикс не срабатывает - с чего начать поиск причины

Проверяю по порядку: правильно ли указан модуль в первом параметре AddEventHandler, актуально ли название события для установленной версии модуля (некоторые события переименовывались между релизами), подключается ли вообще файл с регистрацией на нужном хите, и не срезает ли managed cache вызов события, если он висит внутри закешированного компонента.

Можно ли обработчиком остановить стандартное действие Битрикса

Да, но только на before-событиях (OnBeforeSaleOrderSaved и аналогичные). Внутри такого обработчика нужно бросить исключение BitrixMainSystemException с описанием причины или добавить ошибку через $event->getParameter(‘ERRORS’) в зависимости от типа события - само действие после этого прерывается, а пользователь видит понятное сообщение вместо белого экрана.

Чем обработчики событий отличаются от агентов Битрикса

Обработчик реагирует на конкретное действие в моменте - сохранение заказа, добавление пользователя. Агент выполняется по расписанию через cron независимо от действий пользователей: подходит для периодических выгрузок, синхронизации остатков или рассылок, а не для мгновенной реакции на событие.

Как понять, в каком порядке выполнятся несколько обработчиков одного события

По возрастанию значения параметра sort, который передаётся четвёртым аргументом в AddEventHandler (по умолчанию 100). Если два обработчика зарегистрированы с одинаковым sort, порядок определяется очередностью подключения файлов - рассчитывать на него нельзя, поэтому для критичной по порядку логики sort стоит указывать явно.

Есть задача?

Обсудим в мессенджере

Расскажите, что нужно сделать — отвечу в течение 4 часов в рабочее время. Первая консультация бесплатно.

Самозанятый Калинкин Н. А. · работаю с физлицами и юрлицами

Продолжая пользование настоящим сайтом Вы выражаете своё согласие на обработку Ваших персональных данных (файлов куки) с использованием Yandex.Metrika.
Понятно