Вступление

События Laravel предоставляют простую реализацию наблюдателя, позволяющую вам подписываться и прослушивать различные события, которые происходят в вашем приложении. Классы событий обычно хранятся в каталоге, а их слушатели - в . Не беспокойтесь, если вы не увидите эти каталоги в своем приложении, поскольку они будут созданы для вас, когда вы генерируете события и прослушиватели с помощью консольных команд Artisan.app/Eventsapp/Listeners

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

 

Регистрация событий и слушателей

EventServiceProviderВ комплекте с приложением Laravel обеспечивает удобное место для регистрации всех слушателей событий вашего приложения. listenСвойство содержит массив всех событий (ключи) и их слушателей (значения). Вы можете добавить столько событий в этот массив, сколько требует ваше приложение. Например, давайте добавим OrderShippedсобытие:

/**
 * The event listener mappings for the application.
 *
 * @var array
 */
protected $listen = [
    'App\Events\OrderShipped' => [
        'App\Listeners\SendShipmentNotification',
    ],
];

 

Генерация событий и слушателей

Конечно, создание файлов для каждого события и слушателя вручную затруднительно. Вместо этого добавьте слушателей и события к себе EventServiceProviderи используйте команду. Эта команда будет генерировать любые события или прослушиватели, которые перечислены в вашем . События и слушатели, которые уже существуют, останутся нетронутыми:event:generateEventServiceProvider

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) {
    //
});

 

Обнаружение событий

Обнаружение событий доступно для Laravel 5.8.9 или новее.

Вместо регистрации событий и прослушивателей вручную в $listenмассиве EventServiceProvider, вы можете включить автоматическое обнаружение событий. Когда обнаружение событий включено, Laravel автоматически найдет и зарегистрирует ваши события и слушателей, отсканировав Listenersкаталог вашего приложения . Кроме того, любые явно определенные события, перечисленные в, EventServiceProviderвсе равно будут зарегистрированы.

Laravel находит прослушиватели событий путем сканирования классов слушателей с использованием отражения. Когда 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;
}

По умолчанию все прослушиватели в каталоге Listeners вашего приложения будут сканироваться. Если вы хотите определить дополнительные каталоги для сканирования, вы можете переопределить 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:cacheevent:clear

Команда может быть использована для отображения списка всех событий и слушателей , зарегистрированных приложением.event:list

 

Определение событий

Класс события - это контейнер данных, который содержит информацию, связанную с событием. Например, предположим, что наше сгенерированное 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Черта используется событие будет корректно сериализовать любые красноречивые модели , если объект события сериализации с помощью РНР serializeфункции.

 

Определение слушателей

Далее, давайте посмотрим на слушателя нашего примера события. Слушатели событий получают экземпляр события в своем handleметоде. Команда автоматически импортирует соответствующий класс событий и напечатает подсказку о событии в методе. В рамках метода вы можете выполнить любые действия, необходимые для ответа на событие:event:generatehandlehandle

<?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...
    }
}

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

Остановка распространения события

Иногда вы можете остановить распространение события на других слушателей. Вы можете сделать это, вернувшись falseиз handleметода вашего слушателя .

 

Прослушиватели событий в очереди

Слушатели в очереди могут быть полезны, если ваш слушатель будет выполнять медленную задачу, такую ​​как отправка электронной почты или отправка 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;
}

 

Доступ к очереди вручную

Если вам нужно вручную получить доступ к заданию deleteи releaseметодам очереди слушателя , вы можете сделать это, используя эту черту. Эта черта импортируется по умолчанию для сгенерированных слушателей и предоставляет доступ к этим методам:Illuminate\Queue\InteractsWithQueue

<?php

namespace App\Listeners;

use App\Events\OrderShipped;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;

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\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;

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\Order;
use App\Events\OrderShipped;
use App\Http\Controllers\Controller;

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));
    }
}

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

 

Подписчики событий

Написание событий подписчиков

Подписчики событий - это классы, которые могут подписываться на несколько событий внутри самого класса, что позволяет вам определять несколько обработчиков событий в одном классе. Подписчики должны определить 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',
    ];
}