В этой статье мы попробуем разобраться как запускать события и как их обрабатывать. Напомню, что событие — это своего рода сообщение, возникающее в определенный момент времени. Некоторые события уже определены в Laravel, но в основном эта задача ложится на плечи разработчика.
И так, у нас есть сообщение. Оно, как правило, содержит определённую информацию. И чтобы получить эту информацию, нужно создать обработчик, который будет «слушать» это событие и, когда событие произойдёт, выполнит указанные в нём действия.
Весь функционал для работы с событиями находится в специальном классе Illuminate\Events\Dispatcher
. И мы будем использовать 2 его метода — fire()
для запуска события и listen()
для регистрации обработчиков. Метод fire()
является всего лишь синонимом метода dispatch()
. Напомню, что мы говорим о Laravel версии 5.4.
Регистрация событий и обработчиков (listeners)
Через EventServiceProvider
Это самый простой вариант. EventServiceProvider — это специальный системный сервис-провайдер, который предназначен конкретно для событий. Он содержит 2 закрытых свойства — $listen
и $subscribe
. Первое предназначено для регистрации событий и обработчиков. Второе — для подписчиков (что это мы разберём ниже).
// App\Providers\EventServiceProvider protected $listen = [ 'App\Events\myEvent' => [ 'App\Listeners\myEventListener', ], ];
Ключи массива — это названия событий, а значения — это обработчики. Обработчиков для одного события может быть несколько. Laravel автоматически зарегистрирует указанные в данном свойстве обработчики для каждого события. В качестве названия события можно указать полное квалификационное имя класса события или просто строку с любым названием. В качестве обработчика события указывается класс, который должен содержать метод handle
. Этот метод будет вызван при срабатывании события. Но Laravel позволяет указать свой метод. Для этого его нужно указать через знак @ — App\Listeners\myEventListener@myMethod
.
В Laravel принято классы событий размещать в папке App\Events
, а файлы обработчиков в папке App\Listeners
.
Классы можно создать вручную, а можно выполнить команду php artisan event:generate
— Laravel сам создаст файлы классов, указанные с свойстве $listen
, и положит их в соответствующие папки.
Ручная регистрация
При данном способе регистрации нам понадобится диспетчер событий Illuminate\Events\Dispatcher
и его метод listen
. Обратиться к диспетчеру можно через фасад Event
или функцию-хелпер app('events')
. Данный способ регистрации позволяет указать в качестве обработчика анонимную функцию или класс обработчика
// EventServiceProvider public function boot() { parent::boot(); # Через фасад (событие - название класса). Класс нужно создать самостоятельно. Event::listen('App\Events\myEventClass', function ($eventObject) { // }); # Через функцию (событие - строка) app('events')->listen('myEvent', function ($foo, $bar) { // }); # Вместо анонимной функции указываем класс app('events')->listen('myEvent', 'App\Listeners\myListener'); // В нём должен быть метод handle # Указываем собственный метод класса app('events')->listen('myEvent', 'App\Listeners\myListener@custom'); } }
И фасад и функция доступны в любом месте приложения, поэтому вызывать их можно и в специальном сервис-провайдере EventServiceProvider
, и в своём сервис-провайдере своего пакета, и в контроллерах, и в сервисах, и даже в файле маршрутов. Главное, зарегистрировать раньше вызова события.
Можно зарегистрировать несколько событий для одного обработчика. Для этого их нужно указать в массиве.
Event::listen(['myEvent1','myEvent2'], function ($eventName, $data) { // });
Вместо указания нескольких событий можно использовать звёздочку *
(так называемый wildcard).
Event::listen('Email.*', function ($eventName, $data) { // Сработает на события Email.init, Email.sending, Email.sent });
Важно знать!
Для событий, использующих wildcard, в функцию обработчика первым параметром всегда передаётся название события и уже со второго параметра ваши данные.
Остановка выполнения обработчиков
Если вам нужно остановить дальнейшее выполнение событий (типа event.stopPropagation()
в javascript), обработчик должен вернуть false
.
Инициирование события
Для запуска события можно использовать фасад Event::fire()
или функцию-хелпер event()
.
/** * Запускает событие и вызывает обработчики. * * @param string|object $event Название события * @param mixed $payload Данные * @param bool $halt Режим вызова обработчиков * @return array|null */ public function fire($event, $payload = [], $halt = false)
Место и условия запуска определяется программистом согласно логике приложения. В качестве агрумента можно указать или объект класса события или название события. В зависимости от этого логика метода несколько отличается.
Если указать объект события, то Laravel трансформирует вызов следующим образом:
- В качестве первого параметра будет указано название класса объекта. Это потому, что в качестве ключей массива событий используется строковое значение (см. первый способ регистрации событий).
- А во второй параметр будет передан объект события. Поэтому, если вы указали свои данные во втором параметре, они будут перезаписаны. Передавать данные нужно в конструктор при создании объекта события.
# Запуск события с передачей объекта события $response = event(new App\Events\myEventClass($data)); # В зарегистрированном обработчике ловим объект события ... public function handle(App\Events\myEventClass $event) { // }
Второй вариант запуска событий — указать строковое название события.
# Запуск события по названию $response = event('myEvent', $data)); // Для передачи несколько значений используйте массив.
Передавать нужно столько данных, столько определено в обработчике.
// Регистрируем обработчик для нескольких событий Event::listen(['myEvent1','myEvent2'], function ($eventName, $data) { if ($eventName == 'myEvent1') { // } else { // } }); ... $response = event('myEvent1', ['myEvent1', array('Данные')]));
Третий параметр метода fire()
включает режим, при котором обработчики выполняются до первого, который вернёт какое-нибудь значение. После этого обработка события прекращается и метод возвращает это значение.
В обычном режиме ($halt = false
) метод возвращает или null
или массив значений, которые возвращают обработчики.
Подписчики (subscribers)
Теперь мы знаем, что слушатели (listeners) — это обработчики события. Давайте разберёмся, что такое подписчики. А подписчики — это всего лишь классы, которые содержат всю логику регистрации и обработки событий.
<?php namespace App\Listeners; class UserEventSubscriber { /** * Обработчик события "login". */ public function onUserLogin($event) {} /** * Обработчик события "logout". */ public function onUserLogout($event) {} /** * Регистрация обработчиков для событий логина и логаута. * * @param Illuminate\Events\Dispatcher $events */ public function subscribe($events) { $events->listen( 'Illuminate\Auth\Events\Login', 'App\Listeners\UserEventSubscriber@onUserLogin' ); $events->listen( 'Illuminate\Auth\Events\Logout', 'App\Listeners\UserEventSubscriber@onUserLogout' ); } }
В данном классе должен быть определён метод subscribe
, в котором регистрируются события. И в этом же классе определяются обработчики зарегистрированных событий. Далее подписчик нужно подключить. Сделать это можно двумя способами:
-
- Указать класс в специальном свойстве
$subscribers
сервис-провайдера EventServiceProvider
- Указать класс в специальном свойстве
<?php namespace App\Providers; use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider; class EventServiceProvider extends ServiceProvider { protected $listen = []; /** * The subscriber classes to register. * * @var array */ protected $subscribe = [ 'App\Listeners\UserEventSubscriber', ]; }
-
- Самостоятельно зарегистрировать в нужном месте, например, в сервис-провайдере своего пакета в методе
boot()
- Самостоятельно зарегистрировать в нужном месте, например, в сервис-провайдере своего пакета в методе
public function boot() { Event::subscribe('App\Listeners\UserEventSubscriber'); }
Заключение
Конечно, я рассмотрел не все возможности функционала событий, но данных знаний хватит для большинства проектов. В дальнейшем вы можете самостоятельно освоить, например, очереди событий. А в следующей статье мы рассмотрим события моделей — их специфику и применение.
П.С. Официальная документация по событиям.