Версия фреймворка: 8.x 5.4 4.2
Это скорректированный автоматический перевод, сделанный при помощи google translate.

Трансляция (broadcast) событий

Введение

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

Например, представьте, что ваше приложение может экспортировать данные пользователя в файл CSV и отправлять этот файл ему по электронной почте. Однако создание этого CSV-файла занимает несколько минут, поэтому вы можете создать и отправить CSV-файл по почте, поместив задание в очередь. Когда файл CSV будет создан и отправлен пользователю, тогда мы можем использовать широковещание для отправки события App\Events\UserDataExported, которое будет получено в JavaScript нашего приложения. Как только событие будет получено, мы можем отобразить сообщение пользователю о том, что его файл CSV был отправлен ему по электронной почте без необходимости в обновлении страницы.

Чтобы помочь вам в создании подобного рода функционала, Laravel упрощает «вещание» серверных событий Laravel через соединение WebSocket. Трансляция ваших событий Laravel позволяет вам использовать одни и те же имена событий и данные между серверным приложением Laravel и клиентским JavaScript-приложением.

Поддерживаемые драйверы

По умолчанию Laravel содержит два серверных драйвера трансляции на выбор: Pusher Channels и Ably. Однако пакеты сообщества, например, laravel-websockets, предлагают дополнительные драйверы трансляции без использования платных провайдеров.

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

Установка на стороне сервера

Чтобы начать использовать трансляцию событий Laravel, нам нужно выполнить некоторую настройку в приложении Laravel, а также установить некоторые пакеты.

Трансляция событий осуществляется серверным драйвером трансляции, который транслирует ваши события Laravel, получаемые браузером клиента через Laravel Echo (библиотека JavaScript). Не волнуйтесь – мы рассмотрим каждую часть процесса установки шаг за шагом.

Конфигурирование

Вся конфигурация трансляций событий вашего приложения хранится в конфигурационном файле config/broadcasting.php. Laravel из коробки поддерживает несколько драйверов трансляции: Pusher Channels, Redis, и драйвер log для локальной разработки и отладки. Кроме того, поддерживается драйвер null, который позволяет полностью отключить трансляцию во время тестирования. В конфигурационном файле config/broadcasting.php содержится пример конфигурации для каждого из этих драйверов.

Поставщик службы трансляции

Перед трансляцией каких-либо событий, вам сначала необходимо зарегистрировать поставщика App\Providers\BroadcastServiceProvider. В новых приложениях Laravel вам нужно только раскомментировать этого поставщика в массиве providers конфигурационного файла config/app.php. Поставщик BroadcastServiceProvider содержит код, необходимый для регистрации маршрутов авторизации трансляции.

Конфигурирование очереди

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

Pusher Channels

Если вы планируете транслировать свои события с помощью Pusher Channels, то вам следует установить PHP SDK Pusher Channels с помощью менеджера пакетов Composer:

composer require pusher/pusher-php-server "^5.0"

Далее, вы должны настроить свои учетные данные Pusher Channels в конфигурационном файле config/broadcasting.php. Пример конфигурации Pusher Channels уже содержится в этом файле, что позволяет быстро указать параметры key, secret, и app_id. Как правило, эти значения должны быть установлены через переменные окружения PUSHER_APP_KEY, PUSHER_APP_SECRET и PUSHER_APP_ID:

PUSHER_APP_ID=your-pusher-app-id
PUSHER_APP_KEY=your-pusher-key
PUSHER_APP_SECRET=your-pusher-secret
PUSHER_APP_CLUSTER=mt1

Конфигурация pusher в файле config/broadcasting.php также позволяет вам указывать дополнительные параметры, которые поддерживаются Pusher, например, cluster.

Далее, вам нужно будет изменить драйвер трансляции на pusher в файле .env:

BROADCAST_DRIVER=pusher

И, наконец, вы готовы установить и настроить Laravel Echo, который будет получать транслируемые события на клиентской стороне.

Ably

Если вы планируете транслировать свои события с помощью Ably, то вам следует установить PHP SDK Ably с помощью менеджера пакетов Composer:

composer require ably/ably-php

Далее, вы должны настроить свои учетные данные Ably в конфигурационном файле config/broadcasting.php. Пример конфигурации Ably уже содержится в этом файле, что позволяет быстро указать параметр key. Как правило, это значение должно быть установлено через переменную окружения ABLY_KEY:

ABLY_KEY=your-ably-key

Далее, вам нужно будет изменить драйвер трансляции на ably в файле .env:

BROADCAST_DRIVER=ably

И, наконец, вы готовы установить и настроить Laravel Echo, который будет получать транслируемые события на клиентской стороне.

Альтернативы с открытым исходным кодом

Пакет laravel-websockets – это пакет для Laravel на «чистом» PHP, совместимый с Pusher. Этот пакет позволяет вам использовать всю мощь трансляции Laravel без использования платных провайдеров WebSocket. Для получения дополнительной информации об установке и использовании этого пакета обратитесь к его официальной документации.

Установка на стороне клиента

Pusher Channels

Laravel Echo – это JavaScript-библиотека, которая позволяет безболезненно подписаться на каналы и прослушивать события, транслируемые вашим драйвером трансляции на стороне сервера. Вы можете установить Echo через менеджер пакетов NPM. В этом примере мы также установим пакет pusher-js, так как мы будем использовать вещатель Pusher Channels:

npm install --save-dev laravel-echo pusher-js

После установки Echo вы готовы создать новый экземпляр Echo в JavaScript вашего приложения. Отличное место для этого – окончание файла resources/js/bootstrap.js, который уже содержится в фреймворке Laravel. По умолчанию пример конфигурации Echo также находится в этом файле – вам просто нужно раскомментировать его:

import Echo from 'laravel-echo';

window.Pusher = require('pusher-js');

window.Echo = new Echo({
    broadcaster: 'pusher',
    key: process.env.MIX_PUSHER_APP_KEY,
    cluster: process.env.MIX_PUSHER_APP_CLUSTER,
    forceTLS: true
});

После того, как вы раскомментировали и настроили конфигурацию Echo в соответствии с вашими потребностями, вы можете скомпилировать исходники вашего приложения:

npm run dev
Чтобы узнать больше о компиляции JavaScript-исходников вашего приложения, обратитесь к документации Laravel Mix.

Использование существующего экземпляра клиента

Если у вас уже есть предварительно настроенный экземпляр клиента Pusher Channels, который вы бы хотели использовать в Echo, то вы можете передать его Echo с помощью свойства конфигурации client:

import Echo from 'laravel-echo';

const client = require('pusher-js');

window.Echo = new Echo({
    broadcaster: 'pusher',
    key: 'your-pusher-channels-key',
    client: client
});

Ably

Laravel Echo – это JavaScript-библиотека, которая позволяет безболезненно подписаться на каналы и прослушивать события, транслируемые вашим драйвером трансляции на стороне сервера. Вы можете установить Echo через менеджер пакетов NPM. В этом примере мы также установим пакет pusher-js.

Вы можете задаться вопросом, зачем нам устанавливать библиотеку pusher-js JavaScript, даже если мы используем Ably для трансляции наших событий. К счастью, Ably имеет режим совместимости Pusher, который позволяет нам использовать протокол Pusher при прослушивании событий в нашем клиентском приложении:

npm install --save-dev laravel-echo pusher-js

Прежде чем продолжить, вы должны включить поддержку протокола Pusher в настройках вашего приложения Ably. Вы можете включить эту функцию в разделе настроек «Protocol Adapter Settings» панели вашего приложения Ably.

После установки Echo вы готовы создать новый экземпляр Echo в JavaScript вашего приложения. Отличное место для этого – окончание файла resources/js/bootstrap.js, который уже содержится в фреймворке Laravel. По умолчанию пример конфигурации Echo также находится в этом файле – вам просто нужно раскомментировать его; однако конфигурация по умолчанию в файле bootstrap.js предназначена для Pusher. Вы можете скопировать конфигурацию ниже, чтобы применить ее к Ably:

import Echo from 'laravel-echo';

window.Pusher = require('pusher-js');

window.Echo = new Echo({
    broadcaster: 'pusher',
    key: process.env.MIX_ABLY_PUBLIC_KEY,
    wsHost: 'realtime-pusher.ably.io',
    wsPort: 443,
    disableStats: true,
    encrypted: true,
});

Обратите внимание, что наша конфигурация Echo для Ably ссылается на переменную окружения MIX_ABLY_PUBLIC_KEY. Значение этой переменной должно быть вашим публичным ключом Ably. Ваш публичный ключ – это часть ключа Ably перед символом :.

После того, как вы раскомментировали и настроили конфигурацию Echo в соответствии с вашими потребностями, вы можете скомпилировать исходники вашего приложения:

npm run dev
Чтобы узнать больше о компиляции JavaScript-исходников вашего приложения, обратитесь к документации Laravel Mix.

Обзор концепции

Трансляция событий Laravel позволяет транслировать серверные события Laravel в JavaScript-приложение на клиентской стороне, используя драйверный подход к WebSockets. В настоящее время Laravel поставляется с драйверами Pusher Channels и Ably. События могут быть легко обработаны на стороне клиента с помощью JavaScript-пакета Laravel Echo.

События транслируются по «каналам», которые могут быть публичными или частными. Любой посетитель вашего приложения может подписаться на публичный канал без какой-либо аутентификации или авторизации; однако, чтобы подписаться на частный канал, пользователь должен быть аутентифицирован и авторизован для прослушивания событий на этом канале.

Пример использования

Прежде чем углубляться в каждый аспект трансляции событий, давайте сделаем общий обзор на примере интернет-магазина.

Предположим, что в нашем приложении у нас есть страница, которая позволяет пользователям просматривать статус доставки своих заказов. Предположим также, что событие OrderShipmentStatusUpdated запускается, когда приложение обрабатывает обновление статуса доставки:

use App\Events\OrderShipmentStatusUpdated;

OrderShipmentStatusUpdated::dispatch($order);

Интерфейс ShouldBroadcast

Когда пользователь просматривает один из своих заказов, мы не хотим, чтобы ему приходилось обновлять страницу для просмотра статуса обновлений. Вместо этого мы хотим транслировать обновления в приложение по мере их создания. Итак, нам нужно пометить событие OrderShipmentStatusUpdated интерфейсом ShouldBroadcast. Это проинструктирует Laravel транслировать событие при его запуске:

<?php

namespace App\Events;

use App\Order;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Queue\SerializesModels;

class OrderShipmentStatusUpdated implements ShouldBroadcast
{
    /**
     * Экземпляр заказа.
     *
     * @var \App\Order
     */
    public $order;
}

Интерфейс ShouldBroadcast требует, чтобы в нашем классе события был определен метод broadcastOn. Этот метод отвечает за возврат каналов, по которым должно транслироваться событие. Пустая заглушка этого метода уже определена в сгенерированных классах событий, поэтому нам нужно только заполнить ее реализацию. Мы хотим, чтобы только создатель заказа мог просматривать статус обновления, поэтому мы будем транслировать событие на частном канале, привязанном к конкретному заказу:

/**
 * Получить каналы трансляции события.
 *
 * @return \Illuminate\Broadcasting\PrivateChannel
 */
public function broadcastOn()
{
    return new PrivateChannel('orders.'.$this->order->id);
}

Авторизация каналов

Помните, что пользователи должны иметь разрешение на прослушивание частных каналов. Мы можем определить наши правила авторизации каналов в файле routes/channels.php нашего приложения. В этом примере нам нужно убедиться, что любой пользователь, пытающийся прослушивать частный канал order.1, на самом деле является создателем заказа:

use App\Models\Order;

Broadcast::channel('orders.{orderId}', function ($user, $orderId) {
    return $user->id === Order::findOrNew($orderId)->user_id;
});

Метод channel принимает два аргумента: имя канала и замыкание, которое возвращает true или false, указывая тем самым, имеет ли пользователь право прослушивать канал.

Все замыкания авторизации получают текущего аутентифицированного пользователя в качестве своего первого аргумента и любые дополнительные параметры в качестве своих последующих аргументов. В этом примере мы используем заполнитель {orderId}, чтобы указать, что часть «ID» имени канала является параметром.

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

Далее все, что остается, – это прослушивать событие в нашем JavaScript-приложении. Мы можем сделать это с помощью Laravel Echo. Во-первых, мы будем использовать метод private для подписки на частный канал. Затем мы можем использовать метод listen для прослушивания события OrderShipmentStatusUpdated. По умолчанию все публичные свойства события будут включены в трансляцию события:

Echo.private(`orders.${orderId}`)
    .listen('OrderShipmentStatusUpdated', (e) => {
        console.log(e.order);
    });

Определение транслируемых событий

Чтобы сообщить Laravel, что какое-то событие должно транслироваться, вы должны реализовать интерфейс Illuminate\Contracts\Broadcasting\ShouldBroadcast в классе события. Этот интерфейс уже импортирован во все классы событий, сгенерированные фреймворком, поэтому вы с легкостью можете добавить его к любому из ваших событий.

Интерфейс ShouldBroadcast требует, чтобы вы реализовали единственный метод: broadcastOn. Метод broadcastOn должен возвращать канал или массив каналов, по которым должно транслироваться событие. Каналы должны быть экземплярами Channel, PrivateChannel или PresenceChannel. Экземпляры Channel представляют собой публичные каналы, на которые может подписаться любой пользователь, в то время как PrivateChannels и PresenceChannels представляют собой частные каналы, для которых требуется авторизация канала:

<?php

namespace App\Events;

use App\Models\User;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Queue\SerializesModels;

class ServerCreated implements ShouldBroadcast
{
    use SerializesModels;

    /**
     * Пользователь, создавший сервер.
     *
     * @var \App\Models\User
     */
    public $user;

    /**
     * Создать новый экземпляр события.
     *
     * @param  \App\Models\User  $user
     * @return void
     */
    public function __construct(User $user)
    {
        $this->user = $user;
    }

    /**
     * Получить каналы трансляции события.
     *
     * @return Channel|array
     */
    public function broadcastOn()
    {
        return new PrivateChannel('user.'.$this->user->id);
    }
}

После реализации интерфейса ShouldBroadcast вам нужно только запустить событие, как обычно. После того, как событие будет запущено, задание в очереди автоматически транслирует событие, используя указанный вами драйвер трансляции.

Имя транслируемого события

По умолчанию Laravel будет транслировать событие, используя имя класса события. Однако вы можете изменить имя транслируемого события, определив для события метод broadcastAs:

/**
 * Имя транслируемого события.
 *
 * @return string
 */
public function broadcastAs()
{
    return 'server.created';
}

Если вы измените имя транслируемого события с помощью метода broadcastAs, то вы должны убедиться, что зарегистрировали ваш слушатель с ведущим символом .. Это проинструктирует Echo не добавлять пространство имен приложения к событию:

.listen('.server.created', function (e) {
    ....
});

Данные трансляции

При трансляции события, все его публичные свойства автоматически сериализуются и транслируются как полезная нагрузка события, что позволяет вам получить доступ к любым его публичным данным из вашего JavaScript-приложения. Так, например, если ваше событие имеет единственное публичное свойство $user, представляющее собой модель Eloquent, то полезная нагрузка при трансляции события будет:

{
    "user": {
        "id": 1,
        "name": "Patrick Stewart"
        ...
    }
}

Однако, если вы хотите иметь более точный контроль над полезной нагрузкой трансляции, то вы можете определить метод broadcastWith вашего события. Этот метод должен возвращать массив данных, которые вы хотите использовать в качестве полезной нагрузки при трансляции события:

/**
 * Получите данные для трансляции.
 *
 * @return array
 */
public function broadcastWith()
{
    return ['id' => $this->user->id];
}

Очередь трансляции

По умолчанию каждое транслируемое событие помещается в очередь по умолчанию и соединение очереди по умолчанию, указанные в вашем конфигурационном файле config/queue.php. Вы можете изменить соединение очереди и имя, используемое вещателем, определив свойства connection и queue в вашем классе события:

/**
 * Имя соединения очереди, которое будет использоваться при трансляции события.
 *
 * @var string
 */
public $connection = 'redis';

/**
 * Имя очереди, в которую нужно поместить задание трансляции.
 *
 * @var string
 */
public $queue = 'default';

Если вы хотите транслировать свое событие с помощью очереди sync вместо драйвера очереди по умолчанию, то вы можете реализовать интерфейс ShouldBroadcastNow вместо ShouldBroadcast:

<?php

use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;

class OrderShipmentStatusUpdated implements ShouldBroadcastNow
{
    //
}

Условия трансляции

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

/**
 * Определить, условия трансляции события.
 *
 * @return bool
 */
public function broadcastWhen()
{
    return $this->order->value > 100;
}

Трансляция и транзакции базы данных

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

Если для параметра after_commit конфигурации вашего соединения с очередью установлено значение false, то вы все равно можете указать, что конкретное транслируемое событие должно быть отправлено после того, как все открытые транзакции базы данных были зафиксированы, путем определения свойства $afterCommit в классе события:

<?php

namespace App\Events;

use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Queue\SerializesModels;

class ServerCreated implements ShouldBroadcast
{
    use SerializesModels;

    public $afterCommit = true;
}
Чтобы узнать больше о том, как обойти эти проблемы, просмотрите документацию, касающуюся заданий в очереди и транзакций базы данных.

Авторизация каналов

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

Определение маршрутов авторизации

Laravel упрощает определение маршрутов для ответа на запросы об авторизации канала. В поставщике App\Providers\BroadcastServiceProvider вашего приложения, вы увидите вызов метода Broadcast::routes. Этот метод зарегистрирует маршрут /broadcasting/auth для обработки запросов авторизации:

Broadcast::routes();

Метод Broadcast::routes автоматически применит посредника web для группы своих маршрутов; однако вы можете передать в метод массив атрибутов маршрута, если хотите изменить присваиваемые им атрибуты:

Broadcast::routes($attributes);

Изменение конечной точки авторизации

По умолчанию Echo будет использовать конечную точку /broadcasting/auth для авторизации доступа к каналу. Однако вы можете указать свою собственную конечную точку авторизации, передав параметр конфигурации authEndpoint вашему экземпляру Echo:

window.Echo = new Echo({
    broadcaster: 'pusher',
    // ...
    authEndpoint: '/custom/endpoint/auth'
});

Определение авторизации канала

Затем нам нужно определить логику, которая фактически будет определять, может ли текущий аутентифицированный пользователь прослушивать указанный канал. Это делается в файле routes/channels.php, находящемся в вашем приложении. В этом файле вы можете использовать метод Broadcast::channel для регистрации замыканий авторизации канала:

Broadcast::channel('orders.{orderId}', function ($user, $orderId) {
    return $user->id === Order::findOrNew($orderId)->user_id;
});

Метод channel принимает два аргумента: имя канала и замыкание, которое возвращает true или false, указывая тем самым, имеет ли пользователь право прослушивать канал.

Все замыкания авторизации получают текущего аутентифицированного пользователя в качестве своего первого аргумента и любые дополнительные параметры в качестве своих последующих аргументов. В этом примере мы используем заполнитель {orderId}, чтобы указать, что часть «ID» имени канала является параметром.

Привязка модели к авторизации

Как и HTTP-маршруты, для маршрутов каналов также могут использоваться неявные и явные привязки модели к маршруту. Например, вместо получения строкового или числового идентификатора заказа вы можете запросить фактический экземпляр модели Order:

use App\Models\Order;

Broadcast::channel('orders.{order}', function ($user, Order $order) {
    return $user->id === $order->user_id;
});
В отличие от привязки модели к HTTP-маршруту, привязка модели канала не поддерживает ограничение неявной привязки модели. Однако это редко представляет собой проблему, потому что большинство каналов можно ограничить на основе уникального первичного ключа одной модели.

Предварительная аутентификация авторизации канала

Частные каналы и каналы присутствия аутентифицируют текущего пользователя через стандартного охранника аутентификации вашего приложения. Если пользователь не аутентифицирован, то авторизация канала автоматически отклоняется, и обратный вызов авторизации никогда не выполняется. Однако вы можете назначить несколько своих охранников, которые должны при необходимости аутентифицировать входящий запрос:

Broadcast::channel('channel', function () {
    // ...
}, ['guards' => ['web', 'admin']]);

Определение класса канала

Если ваше приложение использует много разных каналов, то ваш файл routes/channels.php может стать громоздким. Таким образом, вместо использования замыканий для авторизации каналов вы можете использовать классы каналов. Чтобы сгенерировать новый канал, используйте команду make:channel Artisan. Эта команда поместит новый класс канала в каталог app/Broadcasting вашего приложения:

php artisan make:channel OrderChannel

Затем зарегистрируйте свой канал в файле routes/channels.php:

use App\Broadcasting\OrderChannel;

Broadcast::channel('orders.{order}', OrderChannel::class);

Наконец, вы можете поместить логику авторизации для своего канала в метод join класса канала. Этот метод будет содержать ту же логику, которую вы обычно использовали бы в замыкании при авторизации вашего канала. Вы также можете воспользоваться преимуществами привязки модели канала:

<?php

namespace App\Broadcasting;

use App\Models\Order;
use App\Models\User;

class OrderChannel
{
    /**
     * Создать новый экземпляр канала.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Подтвердить доступ пользователя к каналу.
     *
     * @param  \App\Models\User  $user
     * @param  \App\Models\Order  $order
     * @return array|bool
     */
    public function join(User $user, Order $order)
    {
        return $user->id === $order->user_id;
    }
}
Как и многие другие классы в Laravel, классы каналов будут автоматически разрешены контейнером служб. Таким образом, вы можете указать любые зависимости, необходимые для вашего канала, в его конструкторе.

Трансляция событий

После того как вы определили событие и отметили его интерфейсом ShouldBroadcast, вам нужно только запустить событие, используя метод отправки события. Диспетчер событий заметит, что событие помечено интерфейсом ShouldBroadcast, и поставит событие в очередь для дальнейшей трансляции:

use App\Events\OrderShipmentStatusUpdated;

OrderShipmentStatusUpdated::dispatch($order));

Трансляция событий только остальным пользователям

При создании приложения, использующего трансляцию событий, иногда может потребоваться трансляция события всем подписчикам канала, кроме текущего пользователя. Вы можете сделать это с помощью помощника broadcast и метода toOthers:

use App\Events\OrderShipmentStatusUpdated;

broadcast(new OrderShipmentStatusUpdated($update))->toOthers();

Чтобы лучше понять необходимость использования метода toOthers, давайте представим приложение со списком задач, в котором пользователь может создать новую задачу, введя имя задачи. Чтобы создать задачу, ваше приложение может сделать запрос к URL-адресу /task, который транслирует создание задачи и возвращает JSON-представление новой задачи. Когда ваше JavaScript-приложение получает ответ от конечной точки, оно может напрямую вставить новую задачу в свой список задач следующим образом:

axios.post('/task', task)
    .then((response) => {
        this.tasks.push(response.data);
    });

Однако помните, что мы также транслируем создание задачи. Если ваше JavaScript-приложение также прослушивает это событие, чтобы добавить задачи в список задач, у вас будут дублирующиеся задачи в вашем списке: одна из конечной точки и одна из трансляции. Вы можете решить эту проблему, используя метод toOthers, чтобы указать вещателю не транслировать событие текущему пользователю.

Ваше событие должно использовать трейт Illuminate\Broadcasting\InteractsWithSockets для вызова метода toOthers.

Конфигурирование при использовании метода toOthers

Когда вы инициализируете экземпляр Laravel Echo, соединению назначается идентификатор сокета. Если вы используете глобальный экземпляр Axios для выполнения HTTP-запросов из вашего JavaScript-приложения, то идентификатор сокета будет автоматически прикрепляться к каждому исходящему запросу в заголовке X-Socket-ID. Затем, когда вы вызываете метод toOthers, Laravel извлечет идентификатор сокета из заголовка и проинструктирует вещателя не транслировать никакие соединения с этим идентификатором сокета.

Если вы не используете глобальный экземпляр Axios, то вам необходимо вручную сконфигурировать JavaScript-приложение для отправки заголовка X-Socket-ID со всеми исходящими запросами. Вы можете получить идентификатор сокета, используя метод Echo.socketId:

var socketId = Echo.socketId();

Прием трансляций

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

После того, как вы установили и создали экземпляр Laravel Echo, вы готовы к прослушиванию событий, которые транслируются из вашего приложения Laravel. Сначала используйте метод channel для получения экземпляра канала, затем вызовите метод listen для прослушивания конкретного события:

Echo.channel(`orders.${this.order.id}`)
    .listen('OrderShipmentStatusUpdated', (e) => {
        console.log(e.order.name);
    });

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

Echo.private(`orders.${this.order.id}`)
    .listen(...)
    .listen(...)
    .listen(...);

Покидание канала

Чтобы покинуть канал, вы можете вызвать метод leaveChannel вашего экземпляра Echo:

Echo.leaveChannel(`orders.${this.order.id}`);

Если вы хотите покинуть канал, а также связанные с ним частные каналы и каналы присутствия, вы можете вызвать метод leave:

Echo.leave(`orders.${this.order.id}`);

Пространства имён

Вы могли заметить в приведенных выше примерах, что мы не указали полное пространство имен App\Events для классов событий. Это связано с тем, что Echo автоматически предполагает, что события находятся в пространстве имен App\Events. Однако вы можете изменить корневое пространство имен при создании экземпляра Echo, передав параметр конфигурации namespace:

window.Echo = new Echo({
    broadcaster: 'pusher',
    // ...
    namespace: 'App.Other.Namespace'
});

В качестве альтернативы вы можете добавить к классам событий префикс . при подписке на них с помощью Echo. Это позволит вам всегда указывать полное имя класса:

Echo.channel('orders')
    .listen('.Namespace\\Event\\Class', (e) => {
        //
    });

Каналы присутствия

Каналы присутствия основаны на безопасности частных каналов, но в то же время предоставляя дополнительную функцию осведомленности о том, кто подписан на канал. Это упрощает создание мощных функций приложения для совместной работы, таких как уведомление пользователей, когда другой пользователь просматривает ту же страницу, или перечисление пользователей комнаты чата.

Авторизация каналов присутствия

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

Данные, возвращаемые замыканием авторизации, будут доступны для слушателей событий канала присутствия в вашем JavaScript-приложении. Если пользователь не авторизован для присоединения к каналу присутствия, то вы должны вернуть false или null:

Broadcast::channel('chat.{roomId}', function ($user, $roomId) {
    if ($user->canJoinRoom($roomId)) {
        return ['id' => $user->id, 'name' => $user->name];
    }
});

Присоединение к каналам присутствия

Чтобы присоединиться к каналу присутствия, вы можете использовать метод join Echo. Метод join вернет реализацию PresenceChannel, которая, наряду с методом listen, позволяет вам подписаться на события here, joining и leave.

Echo.join(`chat.${roomId}`)
    .here((users) => {
        //
    })
    .joining((user) => {
        console.log(user.name);
    })
    .leaving((user) => {
        console.log(user.name);
    });

Замыкание here будет выполнено сразу после успешного присоединения к канали и получит массив, содержащий информацию о пользователе для всех других пользователей, которые в настоящее время подписаны на канал. Метод joining будет выполняться, когда новый пользователь присоединяется к каналу, а метод leaving будет выполняться при покидании пользователем канала.

Трансляция на каналы присутствия

Каналы присутствия могут получать события так же, как публичные или частные каналы. Используя пример чата, мы можем захотеть транслировать события NewMessage на канал присутствия комнаты. Для этого мы вернем экземпляр PresenceChannel из метода broadcastOn события:

/**
 * Получить каналы трансляции события.
 *
 * @return Channel|array
 */
public function broadcastOn()
{
    return new PresenceChannel('room.'.$this->message->room_id);
}

Как и в случае с другими событиями, вы можете использовать помощник broadcast и метод toOthers, чтобы исключить текущего пользователя из приема трансляции:

broadcast(new NewMessage($message));

broadcast(new NewMessage($message))->toOthers();

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

Echo.join(`chat.${roomId}`)
    .here(...)
    .joining(...)
    .leaving(...)
    .listen('NewMessage', (e) => {
        //
    });

Клиентские события

При использовании Pusher Channels вы должны включить опцию «Client Events» в разделе «App Settings» вашей панели управления приложения для отправки клиентских событий.

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

Чтобы транслировать клиентские события, вы можете использовать метод whisper Echo:

Echo.private(`chat.${roomId}`)
    .whisper('typing', {
        name: this.user.name
    });

Чтобы прослушивать клиентские события, вы можете использовать метод listenForWhisper:

Echo.private(`chat.${roomId}`)
    .listenForWhisper('typing', (e) => {
        console.log(e.name);
    });

Уведомления

Если связать трансляцию событий с уведомлениями, то ваше JavaScript-приложение может получать новые уведомления по мере их появления без необходимости в обновлении страницы. Перед началом работы обязательно прочтите документацию по использованию канала транслируемых уведомлений.

После того, как вы настроили уведомление для использования трансляции канала, вы можете прослушивать транслируемые события, используя метод notification Echo. Помните, что имя канала должно соответствовать имени класса объекта, получающего уведомления:

Echo.private(`App.Models.User.${userId}`)
    .notification((notification) => {
        console.log(notification.type);
    });

В этом примере все уведомления, отправленные экземплярам App\Models\User через канал broadcast, будут получены в замыкании. Авторизация канала App.Models.User.{id} уже изначально содержится в BroadcastServiceProvider фреймворка Laravel.