Events в Laravel позволяют подписываться на события, которые генерируются на стороне сервера.
3 действия:
1 Создать само событие.
2. Создать обработчик события или подписаться на созданное событие.
3. Вызывать событие.
Классы событий находятся в папке app/Events. Классы обработчиков (или прослушивателей) событий – в папке app/Listeners. А вызывать событие можно в любом месте вашего проекта.
Создание события
Команда artisan: создать класс события. Листинг 26.1 |
php artisan make:event PodcastWasPurchased |
Подписка на события
Сервис-провайдер EventServiceProvider - это удобное место для регистрации классов слушателей событий. В массиве listen перечисляются названия события (в ключе массива) и название класса, который его обрабатывает. Например, для нашего PodcastWasPurchased:
Подписка на события. Листинг 26.2 |
protected $listen = [ 'App\Events\PodcastWasPurchased' => [ 'App\Handlers\Events\EmailPurchaseConfirmation@handle', ], ]; |
Для генерации исполнителя (handler) события используйте artisan-команду handler:event:
Команда handler:event. Листинг 26.3 |
php artisan handler:event EmailPurchaseConfirmation --event=PodcastWasPurchased |
Вызов события
Запускать события можно так:
Запуск события. Листинг 26.4 |
use Event; use App\Events\TimeEvent; Event::fire(new TimeEvent()); |
Вместо фасада Event можно использовать хелпер:
Использование хелпера event для запуска события. Листинг 26.5 |
event(new PodcastWasPurchased($podcast)); |
Слушатели в функциях замыканиях
Чтобы упростить себе работу и не создавать два класса, вы можете создать слушателя в виде функции-замыкания. Сделать это можно в методе boot сервис-провайдера EventServiceProvider:
Прослушиватель событий в функции замыкании. Листинг 26.6 |
Event::listen('App\Events\PodcastWasPurchased', function($event) { // Обработка события... }); |
Event:generate
Использование двух команд - make:event и handler:event - каждый раз, когда вам нужно создать обработчик события - это неудобно. Вместо этого, можно заполнить массив listen в EventServiceProvider:
Массив listen. Листинг 26.7 |
protected $listen = [ 'App\Events\UserLogin' => [ 'App\Listeners\UserLoginListener', ], ]; |
И выполнить artisan-команду event:generate. Эта команда анализирует listen и создает все необходимые классы событий и обработчиков событий:
Event:generate. Листинг 26.8 |
php artisan event:generate |
События моделей
Модели Eloquent инициируют несколько событий, что позволяет вам добавить к ним свои обработчики с помощью следующих методов: creating, created, updating, updated, saving, saved, deleting, deleted, restoring, restored.
Когда первый раз сохраняется новая модель, возникают события creating и created. Если модель уже существовала на момент вызова метода save, вызываются события updating и updated. В обоих случаях также возникнут события saving и saved.
Регистрировать слушателей событий модели можно в вашем сервис-провайдере EventServiceProvider. Например,
Регистрация событий. Листинг 26.9 |
public function boot(DispatcherContract $events) { parent::boot($events); User::creating(function($user) { dd($user); }); } |
Подписчики
Подписчики на события (Event Subscribers) - классы, которые могут быть подписаны на несколько событий и содержать сразу несколько обработчиков событий. Такой класс должен иметь метод subscribe, который принимает в аргументах инстанс диспетчера событий:
Класс подписчик событий. Листинг 26.10 |
class UserEventHandler { /** * Событиеlogin. */ public function onUserLogin($event) { // } /** * Событие logout. */ public function onUserLogout($event) { // } /** * Регистрация подписчиков в методе subscriber. * * @param Illuminate\Events\Dispatcher $events * @return array */ public function subscribe($events) { $events->listen('App\Events\UserLoggedIn', 'UserEventHandler@onUserLogin'); $events->listen('App\Events\UserLoggedOut', 'UserEventHandler@onUserLogout'); } } |
После того как класс определён, его можно зарегистрировать следующим образом:
Регистрация подписчика. Листинг 26.11 |
$subscriber = new UserEventHandler; Event::subscribe($subscriber); |
Пример использования событий
У нас имеется таблица users, которой соответсвует следующая модель
Модель User. Листинг 26.12 |
namespace App; use Illuminate\Auth\Authenticatable; use Illuminate\Database\Eloquent\Model; use Illuminate\Auth\Passwords\CanResetPassword; use Illuminate\Foundation\Auth\Access\Authorizable; use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract; use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract; use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract; class User extends Model implements AuthenticatableContract,AuthorizableContract,CanResetPasswordContract { use Authenticatable, Authorizable, CanResetPassword; protected $table ='users'; protected $fillable = ['username', 'password', 'blocked']; protected $hidden = ['password', 'remember_token']; } |
Наша задача: когда из админки блокируем пользователя, полю blocked присваиваем значение 1 или, наоборот, при разблокировке blocked присваиваем 0. Мы должны записывать данные действие в лог. И это мы реализуем с помощью event.
Есть контроллер UserController, в котором есть два метода – один блокирует пользователя, второй разблокирует пользователя.
Метод блокировки пользователя:
Метод lock. Листинг 26.13 |
public function lock($id) { $user = User::find($id); if($user){ $user->blocked = 1; $user->save(); return redirect()->back()->with('message','saved'); } return redirect()->back()->with('errMessage','error'); } |
Рассмотрим подробнее этот метод. В метод lock передается параметр $id, где $id – это ID пользователя, которого мы хотим заблокировать. Дальше мы ищем пользователя по его ID, необходимо для того, чтобы избежать блокировки несуществующего пользователя. Если пользователь найден, то атрибуту blocked присваиваем значение 1 и сохраняем. Дальше редиректим обратно с сообщением «saved».
И второй метод разблокировки пользователя:
Метод unlock. Листинг 26.14 |
public function unlock($id) { $user = User::find($id); if($user){ $user->blocked = 0; $user->save(); return redirect()->back()->with('message','saved'); } return redirect()->back()->with('errMessage','error'); } |
Данный метод аналогичен предыдущему, кроме того, что мы атрибуту blocked присваиваем значение 0.
Теперь можно перейти к решению нашей задачи. Первое - создадим таблицу logs со следующей структурой:
id
user_id
data
created_at
Где user_id – ID пользователя, который осуществил блокировку (мы же в админке работаем только авторизованным пользователем), data – это поле в которое мы будем записывать «ID: $id Status: $blocked» $id – это ID блокируемого или разблокируемого пользователя, а $blocked – это статус: 1- заблокирован, 0 — не заблокирован.
Теперь перейдем к созданию event в Laravel 5. Для этого в начале откроем файл app/Providers/EventServiceProvider.php.
И в свойстве $listen добавим следующий код
Свойство $listen файла EventServiceProvider. Листинг 26.15 |
'App\Events\AddLogs' => [ 'App\Handlers\Events\Log@handle', ], |
Мы добавили в массив ключ и значение, где ключем является событие (event) AddLogs, а элементом массив его слушателе (listener). В нашем случае массив состоит из одного слушателя Log.
Теперь запустим команду artisan для генерации файлов события (event) и слушателя (listener):
Генерация файлов события. Листинг 26.16 |
php artisan event:generate |
У нас появились два файла: App\Events\AddLogs.php и App\Handlers\Events\Log.php.
Файл AddLogs.php. Листинг 26.17 |
namespace App\Events; use App\Events\Event; use Illuminate\Queue\SerializesModels; use Illuminate\Contracts\Broadcasting\ShouldBroadcast; class AddLogs extends Event { use SerializesModels; /** * Create a new event instance. * * @return void */ public function __construct() { } /** * Get the channels the event should be broadcast on. * * @return array */ public function broadcastOn() { return []; } } |
Изменим его, с учетом того, что в наше событие надо передать два параметра $user_id и $data, которые event передаст дальше слушателю.
Измененный файл события AddLogs.php. Листинг 26.18 |
namespace App\Events; use App\Events\Event; use Illuminate\Queue\SerializesModels; use Illuminate\Contracts\Broadcasting\ShouldBroadcast; class AddLogs extends Event { use SerializesModels; public $user_id; public $data; /** * Create a new event instance. * * @return void */ public function __construct($user_id,$data) { $this->user_id = $user_id; $this->data = $data; } /** * Get the channels the event should be broadcast on. * * @return array */ public function broadcastOn() { return []; } } |
Рассмотрим файл слушателя событий.
Слушатель событий, файл Log.php. Листинг 26.19 |
namespace App\Handlers\Events; use App\Events\AddLogs; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Queue\InteractsWithQueue; class Log { /** * Create the event handler. * * @return void */ public function __construct() { // } /** * Handle the event. * * @param AddLogs $event * @return void */ public function handle(AddLogs $event) { } } |
Изменим файл слушателя.
Измененный файл слушателя Log.php. Листинг 26.20 |
namespace App\Handlers\Events; use App\Log; use App\Events\AddLogs; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Queue\InteractsWithQueue; class Log { /** * Create the event handler. * * @return void */ public function __construct() { // } /** * Handle the event. * * @param AddLogs $event * @return void */ public function handle(AddLogs $event) { Adminlog::create([ 'user_id' => $event->user_id, 'data' => $event->data, ]); } } |
Наш event готов к использованию.
Давайте вернемся к контроллеру UserController и поправим методы lock и unlock – запустим наше событие. Это можно сделать при помощи метода fire фасада Event.
Метод блокировки:
Метод lock. Листинг 26.21 |
public function lock($id) { $user = User::find($id); if($user){ $user->blocked = 1; $user->save(); //вызываем event Event::fire(new AddLogs(Auth::user()->id, 'ID: '.$user->id.' Status: 1')); return redirect()->back()->with('message','saved'); } return redirect()->back()->with('errMessage','error'); } |
Метод разблокировки
Метод unlock. Листинг 26.22 |
public function unlock($id) { $user = User::find($id); if($user){ $user->blocked = 0; $user->save(); //вызываем event Event::fire(new AddLogs(Auth::user()->id,'ID: '.$user->id.' Status: 0')); return redirect()->back()->with('message','saved'); } return redirect()->back()->with('errMessage','error'); } |