Обнаружение событий доступно для Laravel 5.8.9 и выше. {note} Event Discovery is available for Laravel 5.8.9 or later.
События
Содержание:
- Введение
- Регистрация событий и слушателей
- Определение событий
- Определение слушателей
- Слушатели очереди событий
- Отправка событий
- Подписчики событий
Введение
События Ларавел обеспечивают простую реализацию наблюдателя, позволяя вам подписаться и прослушивать
различные события, которые происходят в вашем приложении. Классы событий обычно хранятся в папке
app/Events
, в то время как их слушатели располагаются в app/Listeners
.
Не стоит беспокоиться, если вы не видите эти директории в вашем приложении, потому что они будут
созданы при генерации событий и слушателей во время использования команд Artisan.
События выступают с качестве отличного способо разделить разнообразные аспекты вашего приложения,
в силу того, что одиночное событие может иметь несколько слушателей, которые не зависят друг от друга.
Например, вы можете захотеть отправить уведомление Slack вашему пользователю какждый раз,
когда появляется заявка. Вместо соединения вашего кода обработки заказа с уведомлениями Slack,
вы можете запустить событие OrderShipped
, которое слушатель может получить
и трансформировать в уведомление Slack.
Регистрация событий и слушателей
EventServiceProvider
, кключённый в базовый фреймворк Ларавел предоставляет
удобное место для регистрации всех слушателей вашего приложения. Свойство listen
содержит массив элементов (ключей) и их слушателей (знечений). Вы можете добавить так много
событий в этот массив, как это требуется для вашего приложения. Например, давайте добавим
событие OrderShipped
:
/**
* The event listener mappings for the application.
*
* @var array
*/
protected $listen = [
'App\Events\OrderShipped' => [
'App\Listeners\SendShipmentNotification',
],
];
Генерация событий и слушателей
Конечно же, это очень обременительно создавать файлы и слушателя для каждого событияи. Вместо этого
необходимо добавить события в ваш EventServiceProvider
и использовать команду
event:generate
. Эта команда создаст любые события или слушатели, которые перечислены
в вашем файле EventServiceProvider
. События и слушатели, которые уже существую остануться
нетронутыми:
php artisan event:generate
Ручная регистрация событий
Обычно, события должны регистрироваться через EventServiceProvider
и массив
$listen
; Однако, вы можете также регистрировать события основанные на замыкании
в методе boot
вашего EventServiceProvider
:
/**
* Register any other events for your application.
*
* @return void
*/
public function boot()
{
parent::boot();
Event::listen('event.name', function ($foo, $bar) {
//
});
}
Шаблон слушателей события
Вы даже можете зарегистрировать слушателей используя *
как параметр шаблона,
что позволит вам поймать несколько событий для одного и того же слушателя. Шаблон слушателей
получают имя события в качестве первого аргумента, и массив данных события в качестве второго:
Event::listen('event.*', function ($eventName, array $data) {
//
});
Обнаружение событий
Вместо регистрации событий и слушателей вручную в массиве $listen
в
EventServiceProvider
, вы можете разрешить автоматическое обнаружение событий.
Когда обнаружение событий включено, Laravel автоматически найдет и зарегистрирует ваши
события и слушателей путём сканирования папки Listeners
вашего приложения.
Дополнительно, все явные события перечесленные в EventServiceProvider
также будут регистрироваться.
Laravel находит слушателей событий путём сканирования классов слушателя. Когда фреймворк находит
любой метод из класса слушателя, который начинается с handle
, Laravel зарегистрирует
эти методы как слушатели событий для события, которое вписано в подпись метода:
use App\Events\PodcastProcessed;
class SendPodcastProcessedNotification
{
/**
* Handle the given event.
*
* @param \App\Events\PodcastProcessed
* @return void
*/
public function handle(PodcastProcessed $event)
{
//
}
}
По умолчанию, открытие событий отключено, но вы можете включить его путём переписывания метода
shouldDiscoverEvents
для вашего EventServiceProvider
:
/**
* Determine if events and listeners should be automatically discovered.
*
* @return bool
*/
public function shouldDiscoverEvents()
{
return true;
}
По умолчанию, все слушатели внутри соответсвующей папки будут просканированы. Если вы хотите
определить дополнительную папку для сканирования, вам необходимо переписать метод
discoverEventsWithin
в вашем EventServiceProvider
:
/**
* Get the listener directories that should be used to discover events.
*
* @return array
*/
protected function discoverEventsWithin()
{
return [
$this->app->path('Listeners'),
];
}
На сервере, вам скорее всего не захочется, чтобы фреймворк сканировал всех слушателей
для каждого запроса. Следовательно, по время процесса разработки, вам необходимо выполнить
команду Artisan event:cache
, чтобы закешировать все события и слушателей для
вашего приложения. Этот файл (манифест) будет использован фреймворком для ускорения процесса
регистрации. Команда event:clear
может быть использована для уничтожения кэша.
Определение событий
Класс события — это контейнер данных, который хранит информацию связанную с событием. Например,
давайте предположим, что сгенерированное событие OrderShipped
будет получена
как объект Eloquent ORM:
<?php
namespace App\Events;
use App\Order;
use Illuminate\Queue\SerializesModels;
class OrderShipped
{
use SerializesModels;
public $order;
/**
* Create a new event instance.
*
* @param \App\Order $order
* @return void
*/
public function __construct(Order $order)
{
$this->order = $order;
}
}
Как вы можете видеть, этот класс события не содержит логики. Это контейнер для экземпляра
Order
, который был оформлен. Трейт SerializesModels
используемый
событием элегантно проведёт сериализацию любых моделей Eloquent, если объект сериализуется
с помощью функции PHP serialize
.
Определение слушателей
Далее, давайте взглянем на слушателя для нашего примера события. Слушатели события получают
экземпляр события в методе handle
. Команда event:generate
автоматически
импортирует нужный класс и вписывает событие в метод handle
. Внутри метода
handle
, вы можете выполнять любые действия необходимые для ответа событию:
<?php
namespace App\Listeners;
use App\Events\OrderShipped;
class SendShipmentNotification
{
/**
* Create the event listener.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* @param \App\Events\OrderShipped $event
* @return void
*/
public function handle(OrderShipped $event)
{
// Access the order using $event->order...
}
}
Остановка распространения события
Иногда вы можете захотеть остановить распространение события для слушателей. Для этого вам необходимо
вернуть false
из метода handle
вашего слушателя.
Слушатели очереди событий
Очередь слушателй может быть выгодной, если ваш слушатель собирается выполнить медленную задачу, такую как отправка e-mail или выполнение HTTP запроса. Перед тем, как начать работать с очередями слушателей, убедитесь в том, что настроили ваши очереди и запустите очередь слушателя на сервере или локальной среде разработки.
Чтобы указать какой слушатель должен быть помещён в очередь, добавьте интерфейс ShouldQueue
в класс слушателя. Слушатели сгенерированные командой Artisan event:generate
уже имеют этот
интерфейс импортируемый в текущее пространство имен, поэтому вы можете этим пользоваться:
<?php
namespace App\Listeners;
use App\Events\OrderShipped;
use Illuminate\Contracts\Queue\ShouldQueue;
class SendShipmentNotification implements ShouldQueue
{
//
}
И это все! Теперь, когда слушатель вызывается для события, он автоматически будет добавлен в очередь диспетчером событий используя систему очередей Laravel. Если не было выкинуто ни одно исключение при выполнении слушателя в очереди, задание очереди будет автоматически удалено после завершения процесса.
Настройка соединения и имени очереди
Если вы хотите настроить соединение очереди, имя очереди или время задержки очереди прослушивателя событий,
вы можете определить параметры $connection
, $queue
, или $delay
для класса слушателя:
<?php
namespace App\Listeners;
use App\Events\OrderShipped;
use Illuminate\Contracts\Queue\ShouldQueue;
class SendShipmentNotification implements ShouldQueue
{
/**
* The name of the connection the job should be sent to.
*
* @var string|null
*/
public $connection = 'sqs';
/**
* The name of the queue the job should be sent to.
*
* @var string|null
*/
public $queue = 'listeners';
/**
* The time (seconds) before the job should be processed.
*
* @var int
*/
public $delay = 60;
}
Добавления слушателя в очередь с условием
Иногда вам может быть необходимо определить, какого слушателя необходимо добавить
в очередь основываясь на некоторых данных, которые доступны только "на лету".
Для выполнения такой задачи, метод shouldQueue
может быть добавлен
слушателю, чтобы определить, должен ли слушатель быть помещён в очередь
и выполняться синхронно:
<?php
namespace App\Listeners;
use App\Events\OrderPlaced;
use Illuminate\Contracts\Queue\ShouldQueue;
class RewardGiftCard implements ShouldQueue
{
/**
* Reward a gift card to the customer.
*
* @param \App\Events\OrderPlaced $event
* @return void
*/
public function handle(OrderPlaced $event)
{
//
}
/**
* Determine whether the listener should be queued.
*
* @param \App\Events\OrderPlaced $event
* @return bool
*/
public function shouldQueue(OrderPlaced $event)
{
return $event->order->subtotal >= 5000;
}
}
Ручной доступ к очереди
Если вам необходимо получить доступ вручную к исходным методам задания очереди слушателя
delete
и release
, вы можете сделать это используя трейт
Illuminate\Queue\InteractsWithQueue
. Этот трейт импортируется по умолчанию
и предовставляет доступ к этим методам:
<?php
namespace App\Listeners;
use App\Events\OrderShipped;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
class SendShipmentNotification implements ShouldQueue
{
use InteractsWithQueue;
/**
* Handle the event.
*
* @param \App\Events\OrderShipped $event
* @return void
*/
public function handle(OrderShipped $event)
{
if (true) {
$this->release(30);
}
}
}
Обработка невыполненных заданий
Иногда может так случится, что очередь слушателей события потерпела неудачу. Если прослушиватель
очереди превышает максимальное число попыток, как определено, метод failed
будет
вызван для вашего слушателя. Метод failed
получает экземпляр события и исключение,
которое вызвало неудачу:
<?php
namespace App\Listeners;
use App\Events\OrderShipped;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
class SendShipmentNotification implements ShouldQueue
{
use InteractsWithQueue;
/**
* Handle the event.
*
* @param \App\Events\OrderShipped $event
* @return void
*/
public function handle(OrderShipped $event)
{
//
}
/**
* Handle a job failure.
*
* @param \App\Events\OrderShipped $event
* @param \Exception $exception
* @return void
*/
public function failed(OrderShipped $event, $exception)
{
//
}
}
Отправка событий
Для отправки события, вам необходимо передать экземпляр события в помощник event
.
Этот помощник отправит событие по всем его зарегистрированным слушателям. В силу того, что помощник
event
доступен глобально, вы можете вызвать его из любой точки приложения:
<?php
namespace App\Http\Controllers;
use App\Events\OrderShipped;
use App\Http\Controllers\Controller;
use App\Order;
class OrderController extends Controller
{
/**
* Ship the given order.
*
* @param int $orderId
* @return Response
*/
public function ship($orderId)
{
$order = Order::findOrFail($orderId);
// Order shipment logic...
event(new OrderShipped($order));
}
}
Подписчики событий
Написание подписчиков событий
Подписчики событий — это классы, которые могут быть подписаны на несколько событий
из самого класса. Что позволяет вам определить несколько обработчиков внутри одиночного класса.
Подписчики должны определить метод subscribe
, которому будет передан экземпляр
события. Вы можете вызвать метод listen
для данного отправителя,
чтобы зарегистрировать слушателей событий:
<?php
namespace App\Listeners;
class UserEventSubscriber
{
/**
* Handle user login events.
*/
public function handleUserLogin($event) {}
/**
* Handle user logout events.
*/
public function handleUserLogout($event) {}
/**
* Register the listeners for the subscriber.
*
* @param \Illuminate\Events\Dispatcher $events
*/
public function subscribe($events)
{
$events->listen(
'Illuminate\Auth\Events\Login',
'App\Listeners\UserEventSubscriber@handleUserLogin'
);
$events->listen(
'Illuminate\Auth\Events\Logout',
'App\Listeners\UserEventSubscriber@handleUserLogout'
);
}
}
Регистрация подписчиков событий
После написания подписчика, вы готовы зарегистрировать его с отправителем события.
Вы можете зарегистрировать подписчиков используя свойство $subscribe
для EventServiceProvider
. Например, давайте добавим
UserEventSubscriber
в список:
<?php
namespace App\Providers;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider
{
/**
* The event listener mappings for the application.
*
* @var array
*/
protected $listen = [
//
];
/**
* The subscriber classes to register.
*
* @var array
*/
protected $subscribe = [
'App\Listeners\UserEventSubscriber',
];
}