Версія фреймворка: 8.x

Події

Вступ

Події Laravel забезпечують просту реалізацію Observers(Спостерігачі)в, що дозволяє підписатися та слухати різні події, що відбуваються у вашому додатку. Класи подій зазвичай зберігаються вapp/Eventsв той час як їхні Listeners зберігаються вapp/Listeners. Не хвилюйтеся, якщо ви не бачите цих каталогів у своїй програмі, оскільки вони будуть створені для вас, коли ви створюєте події та Listeners за допомогою команд консолі Artisan.

Події служать чудовим способом розділити різні аспекти вашої програми, оскільки в одній події може бути кілька Listeners, які не залежать один від одного. Наприклад, ви можете надіслати Notification Slack своєму користувачеві кожного разу, коли замовлення відправляється. Замість того, щоб поєднувати код обробки замовлень із кодом Notification Slack, ви можете піднятиOrderShippedподія, яку Listener може отримати та перетворити на Notification Slack.

Реєстрація подій та Listeners

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

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

Генерування подій та Listeners

Звичайно, ручне створення файлів для кожної події та Listenerа є громіздким. Натомість додайте Listeners та події до свогоEventServiceProviderі використовуватиevent:generateкоманди. Ця команда генерує будь-які події або Listeners, перелічені у вашомуEventServiceProvider. Події та Listeners, які вже існують, залишаться незайманими:

php artisan event:generate

Реєстрація подій вручну

Як правило, події слід реєструвати черезEventServiceProvider``$listenмасив; однак ви також можете реєструвати події на основі закриття вручну вbootметод вашогоEventServiceProvider:

use App\Events\PodcastProcessed;

/**
 * Register any other events for your application.
 *
 * @return void
 */
public function boot()
{
    Event::listen(function (PodcastProcessed $event) {
        //
    });
}

Listeners анонімних подій, які можна чекати в чергу

При реєстрації прослуховувачів подій вручну, ви можете обернути закриття прослуховувача всерединіIlluminate\Events\queueableфункція, щоб доручити Laravel виконати Listenerа за допомогоючерга:

use App\Events\PodcastProcessed;
use function Illuminate\Events\queueable;
use Illuminate\Support\Facades\Event;

/**
 * Register any other events for your application.
 *
 * @return void
 */
public function boot()
{
    Event::listen(queueable(function (PodcastProcessed $event) {
        //
    }));
}

Як і завдання в черзі, ви можете використовуватиonConnection,onQueue, іdelayметоди налаштування виконання прослуховувача в черзі:

Event::listen(queueable(function (PodcastProcessed $event) {
    //
})->onConnection('redis')->onQueue('podcasts')->delay(now()->addSeconds(10)));

Якщо ви хочете усунути анонімні помилки Listeners, що стоять у черзі, ви можете надати закриття дляcatchметод при визначенніqueueableListener:

use App\Events\PodcastProcessed;
use function Illuminate\Events\queueable;
use Illuminate\Support\Facades\Event;
use Throwable;

Event::listen(queueable(function (PodcastProcessed $event) {
    //
})->catch(function (PodcastProcessed $event, Throwable $e) {
    // The queued listener failed...
}));

Listeners подій підстановки

Ви навіть можете зареєструвати Listeners за допомогою*як підстановочний параметр, що дозволяє ловити кілька подій на одному Listeners. Listeners підстановки отримують назву події як перший аргумент, а весь масив даних про події - як другий аргумент:

Event::listen('event.*', function ($eventName, array $data) {
    //
});

Відкриття подій

Замість того, щоб реєструвати події та Listeners вручну у$listenмасивEventServiceProvider, ви можете ввімкнути автоматичне виявлення подій. Коли увімкнено виявлення подій, Laravel автоматично буде знаходити та реєструвати ваші події та Listeners, скануючи вашу програмуListenersкаталог. Крім того, будь-які чітко визначені події, перелічені вEventServiceProviderвсе одно буде зареєстровано.

Laravel знаходить Listeners подій, скануючи класи Listeners за допомогою рефлексії. Коли Laravel знаходить будь-який метод класу Listenerа, який починається з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 в каталозі Listeners вашої програми. Якщо ви хочете визначити додаткові каталоги для сканування, ви можете замінитиdiscoverEventsWithinметод у вашомуEventServiceProvider:

/**
 * Get the listener directories that should be used to discover events.
 *
 * @return array
 */
protected function discoverEventsWithin()
{
    return [
        $this->app->path('Listeners'),
    ];
}

У виробництві ви, швидше за все, не хочете, щоб фреймворк сканував усіх ваших Listeners на кожен запит. Тому під час процесу розгортання вам слід запуститиevent:cacheКоманда Artisan: кешувати маніфест усіх подій вашого додатка та Listeners. Цей маніфест буде використовуватися фреймворком для пришвидшення процесу реєстрації події.event:clearкоманда може бути використана для знищення кешу.

Theevent:listкоманда може використовуватися для відображення списку всіх подій та Listeners, зареєстрованих вашою програмою.

Визначення подій

Клас події - це контейнер даних, який містить інформацію, що стосується події. Наприклад, припустимо, що наш генерованийOrderShippedподія отримуєEloquent ОРМоб'єкт:

<?php

namespace App\Events;

use App\Models\Order;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class OrderShipped
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $order;

    /**
     * Create a new event instance.
     *
     * @param  \App\Models\Order  $order
     * @return void
     */
    public function __construct(Order $order)
    {
        $this->order = $order;
    }
}

Як бачите, цей клас подій не містить логіки. Це контейнер дляOrderекземпляр, який був придбаний.SerializesModelsриса, яка використовується подією, витончено серіалізує будь-які Eloquent моделі, якщо об’єкт події серіалізується за допомогою PHPserializeфункція.

Визначення Listeners

Далі, давайте поглянемо на Listenerа для нашого прикладу події. Listeners подій отримують екземпляр події у своєму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...
    }
}
Ваші прослуховувачі подій можуть також натякати на будь-які залежності, які їм потрібні, від своїх конструкторів. Усі Listeners подій вирішуються через Laravelслужбовий контейнер, тому залежності будуть вводитись автоматично.

Припинення поширення події

Іноді, можливо, ви захочете припинити розповсюдження події іншим Listenerам. Ви можете зробити це, повернувшисьfalseвід вашого Listenerаhandleметод.

Listeners подій у черзі

Listeners в черзі можуть бути корисними, якщо ваш Listener буде виконувати повільні завдання, наприклад, відправляти електронне повідомлення або робити HTTP-запит. Перш ніж розпочати роботу зі Listenerами, які перебувають у черзі, обов’язковоналаштувати свою чергуі запустіть прослуховувач черги на вашому сервері або в локальному середовищі розробки.

Щоб вказати, що Listener повинен бути в черзі, додайтеShouldQueueінтерфейс до класу Listenerа. Listeners, створеніevent:generateКоманда Artisan вже має цей інтерфейс, імпортований у поточний простір імен, тому ви можете використовувати його відразу:

<?php

namespace App\Listeners;

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

class SendShipmentNotification implements ShouldQueue
{
    //
}

Це воно! Тепер, коли цей Listener буде викликаний до події, він автоматично буде поставлений у чергу в диспетчері подій за допомогою Laravel'sсистема черг. Якщо під час виконання прослуховувача чергою не буде вилучено жодних винятків, завдання в черзі автоматично видаляється після завершення обробки.

Налаштування підключення черги та назви черги

Якщо ви хочете налаштувати підключення черги, назву черги або час затримки черги прослуховувача події, ви можете визначити$connection,$queue, або$delayвластивості вашого класу Listenerа:

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

Якщо ви хочете визначити чергу Listenerа під час виконання, ви можете визначити файлviaQueueметод на Listeners:

/**
 * Get the name of the listener's queue.
 *
 * @return string
 */
public function viaQueue()
{
    return 'listeners';
}

Listeners умовно в черзі

Іноді вам може знадобитися визначити, чи слід ставити Listenerа в чергу, виходячи з деяких даних, доступних лише під час виконання. Для цього:shouldQueueметод може бути доданий до Listenerа, щоб визначити, чи слід Listenerа поставити в чергу. ЯкщоshouldQueueметод повертаєfalse, Listener не буде виконаний:

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

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

Якщо вам потрібно вручну отримати доступ до основних завдань черги Listenerаdeleteіreleaseметодами, ви можете зробити це за допомогоюIlluminate\Queue\InteractsWithQueueриса. Ця ознака імпортується за замовчуванням для згенерованих Listeners і забезпечує доступ до таких методів:

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

Обробка невдалих завдань

Іноді ваші прослуховувачі подій у черзі можуть вийти з ладу. Якщо Listener в черзі перевищує максимальну кількість спроб, визначену вашим працівником черги, файлfailedметод буде викликаний для вашого Listenerа.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  \Throwable  $exception
     * @return void
     */
    public function failed(OrderShipped $event, $exception)
    {
        //
    }
}

Диспетчеризація подій

Щоб надіслати подію, ви можете передати примірник події вeventпомічник. Помічник надішле подію всім зареєстрованим Listenerам. Так якeventhelper доступний у всьому світі, ви можете зателефонувати йому з будь-якої точки вашої програми:

<?php

namespace App\Http\Controllers;

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

Крім того, якщо ваша подія використовуєIlluminate\Foundation\Events\Dispatchableриси, ви можете назвати статичнимdispatchметод події. Будь-які аргументи, передані вdispatchметод буде передано конструктору події:

OrderShipped::dispatch($order);
Під час тестування може бути корисним стверджувати, що певні події були надіслані, фактично не викликаючи їх Listeners. Laravelвбудовані помічники для тестуванняробить це чинчем.

Підписники подій

Написання Підписників подій

Абоненти подій - це класи, які можуть підпискити кілька подій із самого класу, що дозволяє визначити кілька обробників подій в межах одного класу. Абоненти повинні визначити asubscribeметод, який буде переданий екземпляру диспетчера подій. Ви можете зателефонувати доlistenдля даного диспетчера для реєстрації Listeners подій:

<?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
     * @return void
     */
    public function subscribe($events)
    {
        $events->listen(
            'Illuminate\Auth\Events\Login',
            [UserEventSubscriber::class, 'handleUserLogin']
        );

        $events->listen(
            'Illuminate\Auth\Events\Logout',
            [UserEventSubscriber::class, 'handleUserLogout']
        );
    }
}

Крім того, ваш абонентsubscribeметод може повернути масив подій до відображень обробників. У цьому випадку відображення прослуховувача подій будуть автоматично зареєстровані для вас:

use Illuminate\Auth\Events\Login;
use Illuminate\Auth\Events\Logout;

/**
 * Register the listeners for the subscriber.
 *
 * @return array
 */
public function subscribe()
{
    return [
        Login::class => [
            [UserEventSubscriber::class, 'handleUserLogin']
        ],

        Logout::class => [
            [UserEventSubscriber::class, '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',
    ];
}