FFCMS Wiki

Официальная документация разработчика и администратора

Инструменты пользователя

Инструменты сайта


core:eventmanager

События и менеджер событий (EventManager)

Система управления содержимым сайта FFCMS 3 поддерживает модель управления событиями. Событие (Event) в пространстве FFCMS - то, что имеет место и происходит при определенных условиях. Ярким примером события является регистрация или авторизация пользователя на сайте.

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

Вы так же можете обозначать события в вашем приложении, тем самым давая другим разработчикам возможность взаимодействовать с ним.

Обозначение события

Для обозначения события в контроллере (или другой составляющей) вашего приложения вам необходимо обратиться к методу run в менеджере событий через единую точку доступа App:

App::$Event->run('event.name', [$params]);

В качестве аргументов функции run необходимо указать название события event.name и в случае необходимости передать те или иные параметры в виде массива.

Более качественная реализация показана ниже на примере контроллера приложения. Обратите внимание, в качестве названия события используется константа, в которой указано имя в виде строки (это удобно для статического использования имени события):

class Demo extends FrontController
{
    const EVENT_ON_INDEX = 'demo.index';
 
    public function actionIndex()
    {
        $model = new MyModel(); // just test code of model init
        // any code there
        App::$Event->run(static::EVENT_ON_INDEX, [
            'model' => $model
        ]);
        // any code there
    }
}

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

Перехват события

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

  1. «Крючок»: перехват в состоянии до наступления события Event→on()
  2. «Прослушка»: Перехват в состоянии после наступления Event→listen()

Перехват события "Крючок" (on)

Данный тип перехвата наступления события происходит ДО его наступления и полезен в том случае, когда необходимо выполнить тот или иной код до наступления события. События типа «крючок» могут быть выполнены только в теле статического метода boot в контроллере вашего приложения.

Следует помнить, что метод boot вашего контроллера вызывается НЕЗАВИСИМО от того активен ли он при текущем пути пользователя сайта. Иными словами, метод boot ЛЮБОГО контроллера будет гарантированно вызван при любой инициации пользовательской сессии. Как наглядный пример взаимодействия с событием, описанным выше приведем следующий пример:

class OtherDemo extends Controller
{
    public static function boot()
    {
        App::$Event->on(Demo::EVENT_ON_INDEX, function($model) {
            $model->someVar = 'value';
            if (mt_rand(0,1) === 0) { // calc 50% random chance
                throw new NotFoundException('50% of unavailable this page');
            }
        });
    }
}

Для опытных разработчиков этого описания будет достаточно, т.к. реализация достаточно схожа с популярными фреймворками, однако давайте рассмотрим данный механизм подробней.

Итак, в статическом методе boot мы вызываем через единую точку доступа App::$Event метод on, в котором передаем 2 аргумента: первый - имя перехватываемого метода (см. выше, мы определили его константой в классе где объявляли событие), второй - анонимная функция, которая будет вызвана и исполнена до наступления события. В аргументе анонимной функции мы приняли переменную $model, которая будет передана при перехвате события (так как была передана при объявлении события). Теперь мы можем изменить свойство someVar в переданной переменной (объекте) $model. Следующим шагом мы с вероятностью в 50% mt_rand(0,1) === 0 выбросим исключение NotFoundException.

Эти две операции перед исполнением события являются самым наглядным примером взаимодействия с событиями в системе ffcms. В качестве практического примера может выступать пример перехвата события user.signup.success при помощи которого мы можем получить регистрационные данные пользователя и к примеру зарегистрировать его в какой-либо внешней базе данных или сервисе без изменения кода приложения идентификации пользователя. Еще один наглядный пример использования перехвата событий - перехват события content.read и изменение содержимого отображаемого материала (к примеру - удаление всех внешних ссылок, замена каких-либо слов или ограничение доступа к контенту в зависимости от группы пользователя).

Перехват события "Просшулка" (listen)

Данный тип перехвата событий предназначен для пост-обработки того или иного события на сайте. Он очень удобен для перехвата данных события для обработки их после его происхождения - выполнения произвольного когда или повторного отображения данных.

Кроме того, данный тип перехвата события имеет определенные плюсы - он может быть вызван практически в любой части кода вашего приложения, в отличии от перехвата по типу «крючек». Прослушка может быть вызвана в контроллерах, моделях, представлениях или даже виджетах и их производных.

В качестве примера приведем код представления нашего «демонстрационного» виджета, который будет повторно отображать краткий заголовок материала контента:

<h1>Current news</h1>
<p><?php
$data = \App::$Event->listen('content.read', function($model) {
    return Str::substr(0, 15, $model->title) . '...';
});
echo ($data !== false && $data !== null) ? $data : 'No data';
?></p>

* не следует воспринимать данный код как эталон - это лишь демонстрация возможности использования событий.

Следует помнить, что перехват событий по типу «Прослушка» не работают «насквозь» на сайте: код, в котором используется вызов события на прослушку должен выполняться на той же странице, где и происходит событие.

Применение перехвата событий

Как мы уже выше показывали - события являются достаточно гибкой реализацией в ffcms. В данном разделе мы приведем несколько примеров того, для каких целей могут быть применены события.

Пример 1. «Прослушка» нескольких событий для динамического отображения блока в шаблоне. Представьте, что мы хотим отображать определенный блок с html кодом на сайте только в том случае, если в данный момент пользователь просматривает список контента или читает определенный элемент контента. Безусловно, реализовать данный механизм мы можем и другими способами (сравнивая URL или запущен тот или иной контроллер) но сделать это можно и при помощи событий. В наш main.php в /layout/ поместим следующий блок:

echo \App::$Event->listen(['content.read', 'content.list'], function() {
    return '<div class="h1">Hello, event!</div>';
});

Пример 2. Перехват логина и пароля пользователя при регистрации для отправки их во внешнюю базу данных для единой регистрации. Реализация будет выполнена в демонстрационном контроллере, методе boot путем передачи логина, email'а и пароля в реализацию расширенной функции:

class Demo extends Controller
{
 
    public static function boot()
    {
        App::$Event->on('user.signup.success', function($model) {
            // some extended function with algorythm of extend db registration
            ExtendRegister::register($model->login, $model->email, $model->password);
        });
    }
}

to be continued

Список стандартных событий

Событие (str) Константа Аргументы Описание
user.login.success User::EVENT_USER_LOGIN_SUCCESS $model ⇒ FormLogin Событие успешной авторизации пользователя на сайте
user.login.fail User::EVENT_USER_LOGIN_FAIL $model ⇒ FormLogin Событие неудачной попытки авторизации пользователя на сайте
user.signup.success User::EVENT_USER_REGISTER_SUCCESS $model ⇒ FormRegister Событие успешной регистрации пользователя на сайте
user.signup.fail User::EVENT_USER_REGISTER_FAIL $model ⇒ FormRegister Событие неудачной попытки регистрации пользователя на сайте
content.read Content::EVENT_CONTENT_READ $model ⇒ EntityContentRead Событие чтения полного содержимого единицы контента
content.list Content::EVENT_CONTENT_LIST $model ⇒ EntityCategoryList Событие чтения списка контента
content.rss.read Content::EVENT_RSS_READ $model ⇒ EntityCategoryList, $feed ⇒ Feed, $channel ⇒ Channel Событие чтения rss ленты
content.tags Content::EVENT_TAG_LIST $model ⇒ ContentEntity Событие чтения списка тегов

Лучшие концепции

  1. События типа «крючек» (on) должны использоваться только в контроллерах в статическом методе boot. Данные события являются полностью сквозными.
  2. Реализация анонимной функции перехвата события не должна быть громоздкой. В случае большого количества операций следует предусмотреть реализацию отдельного класса или метода.
  3. События должны быть объявлены только в контроллерах для избежания путаницы.
  4. Объявлять события необходимо после завершения всех операций изменения данных для избежания подмены данных для сохранения при помощи перехвата события. Более простым языком - не следует давать возможность изменения данных работы приложения до сохранения их в базу данных или иное место.
core/eventmanager.txt · Последние изменения: 2016/06/20 17:08 (внешнее изменение)