События (event) в UMI CMS
Рубрика: Обучение, Тонкости UMI CMS
Сегодня зашел разговор о событиях в ЮМИ и, как оказалось, не все знают и понимают как это работает. В связи с этих хочу попробовать на пальцах обяснить общий принцип данного механизма.
Зачем нам события?
Допустим, вам нужно вклиниться в работу стандартного (!) механизма макросов ЮМИ и видоизменить порядок стандартных (!) действий. Например, отправить уведомление при определенном действии пользователя или добавить проверку. Как это сделать?
Кто-то может влезать напрямую в системный код. Но это плохая практика. Дело в том, что при следующем обновлении все изменения, внесенные в стандартные системные файлы юми, благополучно затрутся. Как же быть?
И тут на помощь к нам приходят события.
Как работают события?
В большинстве стандартных макросов ЮМИ встроены специальные блоки, вызывающие пользовательские методы. Но не все подряд, а только те, которые привязаны к соответствующему идентификатору. Например, в макросе FAQ при добавлении вопроса от пользователя вызывается событие с идентификатором: faq_post_question
. Но пойдем по порядку.
Вся работа строится в 2 этапа.
1. Метод, срабатывающий на событие
В модуле, к которому нужно привязать метод, в файле __custom.php создается метод. Допустим, нам необходимо проверить на пустоту гипотетическое поле name. Тогда код обработчика может выглядеть так:
<?php abstract class __faq_custom { public function onAddQuestion($e) { if($e->getMode() == "before") { $name = (string) getRequest('name'); if(trim($name) === ''){ return false; } } } }; ?>
В качестве параметра в событие передается объект, обязательно содержащий текущий режим: до выполнения действий модуля (before) или после выполнения (after). Тем самым мы не нуждаемся в двух разных точках вызова — достаточно лишь указать Mode.
Режим after может потребоваться если вы хотите сделать обработку полей после сохранения или же отправить уведомление об успешном завершении работы метода (например, уведомление администратору о поступившем вопросе).
2. Привязка метода к событию
Чтобы наше событие сработало необходимо указать, когда это должно произойти.
Для этого создаем там же, в папке модуля (в нашем случае это будет "/classes/modules/faq/") файл с именем custom_events.php и в него прописываем следующее содержимое:
<?php new umiEventListener("faq_post_question", "faq", "onAddQuestion"); ?>
Здесь первым параметром (faq_post_question) выступает название точки возникновения события, вторым параметром (faq) — название модуля. Третий параметр (onAddQuestion) — имя метода, срабатывающего на указанное событие.
Вот собственно и вся хитрость.
Вообще, вся информация изложена достаточно подробно в официальной документации по ЮМИ, однако, чтобы начать успешно работать с событиями, вам будет достаточно и данного описания.
Сен14
13 Ноя 2014 в 17:56
А можно ли снять обработчик событий? Например отменить стандартную отправку уведомлений менеджеру и покупателю после смены статуса заказа, для того чтобы назначить свой обработчик и свою отправку.
Суть вопроса в том, что как изменить стандартное поведение системы, не меняя исходный код?
13 Ноя 2014 в 22:09
Ну, начнем с того, что в настройках уведомлений к интернет-магазину есть специальные флажки:
— Отключить уведомления о смене статуса заказа
— Отключить уведомления о смене статуса оплаты
— Отключить уведомления о смене статуса доставки
Они отключают отправку уведомлений при смене статуса.
Если говорить об отправке уведомлений менеджеру — можно поставить другой E-Mail адрес и пересылать с него только нужные сообщения.
Я это к тому, что есть более простые способы, нежели написание кода. И не стоит усложнять себе жизнь.
Но возможно проблема в чем-то другом и я просто не до конца понял суть?
15 Ноя 2014 в 14:25
Кстати, хорошая идея! Моя задача не в том, чтобы отменить отправку уведомлений, а в том, чтобы заменить нотификатор на свой, который используется в моем расширении для модуля. При смене статуса заказа чтобы высылалось уведомление не стандартным способом, используя шаблоны, а другим способом. Но спасибо. Подключиться к событию в юми легко, подменить обработчик трудно. Например в пресловутом вордпрессе система событий (хуков) несколько гибче.
15 Ноя 2014 в 20:18
Насколько я понял, в данном конкретном случае все прошло как нужно, правильно?
А вообще, если стандартная точка существует, то не вижу никаких сложностей с заменой функционала. Просто необходимо обрабатывать статус «before» у события и возвращать «false» после этого. Тогда дальнейшая обработка не будет выполнена.
Но, в этом случае, придется полностью воспроизводить функционал отключенного места, например, записывая информацию о заказе в базу.
16 Ноя 2014 в 0:15
А, вот как! Спасибо еще раз. Однако, тогда возникает вопрос — цепочка вызова обработчиков события начинается с кастомных обработчиков или с системных? По умолчанию у всех обработчиков установлен приоритет 5. Значит, можно установить своему обработчику приоритет от 0 до 4 и тогда он будет вызван раньше. В официальной документации про приоритеты написано то, что этот функционал пока не работает, на практике пока не проверял. Может вы знаете?
16 Ноя 2014 в 3:31
Честно сказать — так глубоко никогда не копал. Никогда не возникало необходимости переопределять системные обработчики событий, которые, к тому же, идут друг за другом вместе с пользовательскими.
Если же говорить о том, каким образом возможно отследить реальное поведение системы при работе со стеком вызова событий — то я бы обратился к исходному коду. К сожалению, это единственный достоверный и полный источник знаний на текущий момент.
23 Июл 2015 в 0:40
Здравствуйте.
Подскажите, у UMI есть такое событие users_login_successfull. В UMI например это событие используется для подсчета количества авторизаций.
Если авторизоваться не через админку (адрес_сайта/admin) сайта, а с фронтэнда (вывести например форму авторизации на какой либо странице), то это событие не срабатывает. Не сталкивались с таким? Может быть сможете посоветовать куда копать чтоб вызвать это событие именно при авторизации с фронтенда.
Проверял под разными доступами пользователей, глухо, не работает.
И подскажите, можно ли вызвать событие через ajax? Ведь например взяв выше указанное события используемое для подсчета авторизаций, и функцию которая это выполняет (onLogInCount, у UMI реализована в качестве кастомной функции), нельзя к этой функции обратиться, ведь она не расшарена, в permission.php её нет.
Да и в самом ajax в url (в конкретном случае у меня), стоит указание на другую функцию. А мне нужно вызвать событие при условии что выполнится функция указанная в ajax в url.
$.ajax({
type: «post»,
url: «/users/login_do/.json»,
………………
});
23 Июл 2015 в 10:47
Приветствую, Андрей.
Смотрите, в методе login_do, если вы доходите до этапа авторизации и запуска сессии, то явно проставлено вызывать событие:
$oEventPoint = new umiEventPoint(«users_login_successfull»);
$oEventPoint->setParam(«user_id», $user->id);
$this->setEventPoint($oEventPoint);
Я посмотрел на работающей юмке и вижу, что системное событие срабатывает и при авторизации через морду.
Так что тут вопрос скорее не в «несрабатывании» событий, а в недоступности функции события или же в отсутствии привязки функции к событиюм.
Попробуйте проверить эти 2 момента. Возможно, что это исправит ситуацию.