Обработчик события не срабатывает - разбор причин
Обработчик написан и зарегистрирован, а событие проходит мимо него. Разбираем причины по убыванию частоты, начиная со списка зарегистрированных обработчиков.
С чего начать
Смотрим, видит ли платформа обработчик вообще:
$handlers = \Bitrix\Main\EventManager::getInstance() ->findEventHandlers('iblock', 'OnAfterIBlockElementAdd');printf("обработчиков: %d\n", count($handlers));print_r(array_column($handlers, 'CALLBACK'));// SORT в каждой записи показывает порядок вызова обработчиков между собой// пустой список означает, что дело не в коде обработчика, а в регистрацииСписок показывает и постоянные обработчики из базы, и добавленные на текущем запросе. Пустой ответ снимает половину версий сразу: код обработчика тут ни при чём, до него дело не доходит.
Проверяем, что файл регистрации вообще подключается:
// первая строка /local/php_interface/init.php\Bitrix\Main\Diag\Debug::writeToFile(date('H:i:s'), 'init', 'init.log');// файла нет в журнале - значит, подключается другой init.php или никакойФайл обработчиков в своём каталоге отменяет одноимённый файл в каталоге ядра. Скопированный, а не перенесённый файл - типовая причина «код есть, а не работает», и обнаруживается она за одну строку записи в журнал.
Сверяем модуль и имя события:
$em = \Bitrix\Main\EventManager::getInstance();$em->addEventHandler('sale', 'OnSaleOrderSaved', $callback); // модуль sale$em->addEventHandlerCompatible('main', 'OnBeforeUserAdd', $cb2); // старое событие// событие принадлежит модулю: чужой модуль в регистрации даёт тишинуИмя модуля - часть адреса события, а не пояснение. Регистрация того же события с именем другого модуля проходит без ошибок и не срабатывает никогда.
Смотрим, что приходит в сам обработчик:
$em->addEventHandler('iblock', 'OnAfterIBlockElementAdd', static function ($arg) { \Bitrix\Main\Diag\Debug::writeToFile( is_object($arg) ? get_class($arg) : gettype($arg), 'аргумент', 'ev.log'); });// объект вместо массива означает, что нужен совместимый способ регистрацииОдна строка в журнале отвечает сразу на два вопроса: вызывается ли обработчик и в каком виде приходят аргументы. Дальше разбор идёт либо по регистрации, либо по коду внутри обработчика.
Проверяем, что правка вообще идёт через методы платформы:
$element = new CIBlockElement();$element->Update($id, $fields); // события поднимает API, а не база// прямой запрос UPDATE b_iblock_element ... событий не поднимает вовсеПричины
-
Файл с регистрацией не подключается примерно 30% случаев
ПризнакСписок обработчиков пуст, записи из файла регистрации в журнал не попадают.
ПроверкаПишем строку в журнал первой строкой файла и обновляем страницу сайта.
Что делатьПереносим код в подключаемый файл своего каталога: одноимённый файл ядра при нём не читается.
-
Указан не тот модуль или имя события примерно 25% случаев
ПризнакРегистрация проходит без ошибок, обработчик в списке этого события отсутствует.
ПроверкаСверяем имя модуля-владельца и точное написание события по документации.
Что делатьПравим имя модуля и события: регистрация чужого имени не вызывает ошибок и молчит.
-
Нужен совместимый формат обработчика примерно 20% случаев
ПризнакОбработчик вызывается, но аргументы приходят не те и код внутри ничего не делает.
ПроверкаПечатаем полученные аргументы в журнал и смотрим, объект это или привычные значения.
Что делатьДля старых событий ядра берём совместимый способ регистрации: он передаёт позиционные аргументы.
-
Запись идёт мимо события примерно 15% случаев
ПризнакЧерез админку обработчик работает, а при обмене или своём скрипте - нет.
ПроверкаСмотрим, каким способом меняются данные: методами платформы или прямым запросом к базе.
Что делатьПереводим правку на методы платформы: события поднимает API, а не сама база данных.
-
Обработчик отработал, а изменения потерялись примерно 10% случаев
ПризнакЗаписи в журнале есть, но данные сохраняются в исходном виде.
ПроверкаПроверяем, возвращает ли обработчик результат и меняет ли поля по ссылке.
Что делатьВозвращаем значение нужного вида либо правим массив по ссылке: копия изменений никуда не уезжает.
Частые вопросы
Чем регистрация в базе отличается от регистрации на запросе?
Постоянная регистрация хранится в базе и переживает перезагрузку: её делают при установке модуля. Регистрация в подключаемом файле живёт один запрос, не нагружает базу, но её сложнее найти при разборе.
Почему обработчик срабатывает дважды?
Он зарегистрирован и в базе, и в подключаемом файле, либо файл подключается дважды. Список обработчиков события покажет оба вхождения.
Как понять, какие события вообще есть у модуля?
По документации модуля и по вызовам отправки события в его коде. Названия событий не угадываются: опечатка выглядит как отсутствие события.
Обработчик не срабатывает при обмене с 1С.
Обмен пользуется своими методами и поднимает свои события. Ищут событие обмена, а не событие правки элемента вручную.
Можно ли отладить обработчик отладчиком?
На стенде - да, на боевом сайте безопаснее записи в журнал. Строка с аргументами в журнале отвечает на большинство вопросов быстрее пошаговой отладки.
Смежное
-
Как найти нужное событие: поиск по ядру и три системы - проверка имени события по коду ядра
-
События на практике - оглавление подтемы
-
Обработчик меняет данные: рекурсия, флаг, массовые операции - когда обработчик зацикливается
-
Файл инициализации: порядок подключения, что доступно, ошибки - какой файл подключается на самом деле
-
Обработчик события: регистрация, аргументы, отмена действия - как регистрируют правильно
-
Свои события в своём коде: как дать другим точку расширения - обратная сторона механизма
-
Журнал событий: чтение, очистка, свои записи - куда писать отладочные строки
-
Отладка на боевом сайте: журналы, режим ошибок, поиск виновника - инструменты разбора
-
Ядро D7 - устройство ядра целиком
-
Своя логика при обмене: обработчики, защита правок, журнал - события обмена с учётной системой
-
Обработчик срабатывает дважды: разбор причин - обратный случай того же разбора