События (event) в 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

8 комментариев на «События (event) в UMI CMS»

  1. Alexey пишет:
    13 Ноя 2014 в 17:56

    А можно ли снять обработчик событий? Например отменить стандартную отправку уведомлений менеджеру и покупателю после смены статуса заказа, для того чтобы назначить свой обработчик и свою отправку.
    Суть вопроса в том, что как изменить стандартное поведение системы, не меняя исходный код?

    • Ну, начнем с того, что в настройках уведомлений к интернет-магазину есть специальные флажки:
      — Отключить уведомления о смене статуса заказа
      — Отключить уведомления о смене статуса оплаты
      — Отключить уведомления о смене статуса доставки

      Они отключают отправку уведомлений при смене статуса.

      Если говорить об отправке уведомлений менеджеру — можно поставить другой E-Mail адрес и пересылать с него только нужные сообщения.

      Я это к тому, что есть более простые способы, нежели написание кода. И не стоит усложнять себе жизнь.

      Но возможно проблема в чем-то другом и я просто не до конца понял суть?

      • Alexey пишет:
        15 Ноя 2014 в 14:25

        Кстати, хорошая идея! Моя задача не в том, чтобы отменить отправку уведомлений, а в том, чтобы заменить нотификатор на свой, который используется в моем расширении для модуля. При смене статуса заказа чтобы высылалось уведомление не стандартным способом, используя шаблоны, а другим способом. Но спасибо. Подключиться к событию в юми легко, подменить обработчик трудно. Например в пресловутом вордпрессе система событий (хуков) несколько гибче.

        • Насколько я понял, в данном конкретном случае все прошло как нужно, правильно?

          А вообще, если стандартная точка существует, то не вижу никаких сложностей с заменой функционала. Просто необходимо обрабатывать статус «before» у события и возвращать «false» после этого. Тогда дальнейшая обработка не будет выполнена.

          Но, в этом случае, придется полностью воспроизводить функционал отключенного места, например, записывая информацию о заказе в базу.

          • Alexey пишет:
            16 Ноя 2014 в 0:15

            А, вот как! Спасибо еще раз. Однако, тогда возникает вопрос — цепочка вызова обработчиков события начинается с кастомных обработчиков или с системных? По умолчанию у всех обработчиков установлен приоритет 5. Значит, можно установить своему обработчику приоритет от 0 до 4 и тогда он будет вызван раньше. В официальной документации про приоритеты написано то, что этот функционал пока не работает, на практике пока не проверял. Может вы знаете?

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

              Если же говорить о том, каким образом возможно отследить реальное поведение системы при работе со стеком вызова событий — то я бы обратился к исходному коду. К сожалению, это единственный достоверный и полный источник знаний на текущий момент.

  2. Андрей пишет:
    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»,
    ………………
    });

    • Приветствую, Андрей.

      Смотрите, в методе login_do, если вы доходите до этапа авторизации и запуска сессии, то явно проставлено вызывать событие:

      $oEventPoint = new umiEventPoint(«users_login_successfull»);
      $oEventPoint->setParam(«user_id», $user->id);
      $this->setEventPoint($oEventPoint);

      Я посмотрел на работающей юмке и вижу, что системное событие срабатывает и при авторизации через морду.

      Так что тут вопрос скорее не в «несрабатывании» событий, а в недоступности функции события или же в отсутствии привязки функции к событиюм.

      Попробуйте проверить эти 2 момента. Возможно, что это исправит ситуацию.

Ваш отзыв на Alexey