Идёт обновление сайта. Несколько дней возможны сбои в оформлении и переводах. Документация работает — если страница выглядит сломанной, обновите её позже.

Документация
L Laravel L intervention/image
Войти
Главная Laravel 10.x Трансляция событий

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

10.x 7 мар 2026 г.

#Введение

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

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

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

Основные концепции трансляции просты: клиенты подключаются к именованным каналам на фронтенде, а ваше Laravel-приложение транслирует события в эти каналы на бэкенде. Эти события могут содержать любые дополнительные данные, которые вы хотите сделать доступными на фронтенде.

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

По умолчанию Laravel включает три серверных драйвера трансляции на выбор: Laravel Reverb, Pusher Channels и Ably.

Примечание

Перед тем как начать работу с трансляцией событий, убедитесь, что вы ознакомились с документацией 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 содержит код для регистрации маршрутов и обратных вызовов авторизации трансляции.

#Настройка очереди

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

#Reverb

Вы можете установить Reverb с помощью менеджера пакетов Composer:

composer require laravel/reverb

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

php artisan reverb:install

Подробные инструкции по установке и использованию Reverb доступны в документации Reverb.

#Pusher Channels

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

composer require pusher/pusher-php-server

Далее настройте учётные данные Pusher Channels в файле config/broadcasting.php. В этом файле уже есть пример конфигурации Pusher Channels, где можно быстро указать ключ, секрет и 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 также можно указать дополнительные options, поддерживаемые Channels, например кластер.

Затем измените драйвер трансляции на pusher в вашем файле .env:

BROADCAST_DRIVER=pusher

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

#Открытые альтернативы Pusher

soketi предоставляет совместимый с Pusher WebSocket-сервер для Laravel, позволяя использовать все возможности трансляции Laravel без коммерческого провайдера WebSocket. Для получения дополнительной информации об установке и использовании открытых пакетов для трансляции ознакомьтесь с разделом открытые альтернативы.

#Ably

Примечание

В документации ниже описывается использование Ably в режиме совместимости с Pusher. Однако команда Ably рекомендует и поддерживает драйвер и клиент Echo, которые используют уникальные возможности Ably. Для дополнительной информации об использовании драйверов Ably ознакомьтесь с документацией Ably Laravel broadcaster.

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

composer require ably/ably-php

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

ABLY_KEY=your-ably-key

Затем измените драйвер трансляции на ably в вашем файле .env:

BROADCAST_DRIVER=ably

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

#Открытые альтернативы

#Node

Soketi — это WebSocket-сервер на базе Node, совместимый с Pusher для Laravel. В основе Soketi лежит µWebSockets.js, обеспечивающий высокую масштабируемость и скорость. Этот пакет позволяет использовать все возможности трансляции Laravel без коммерческого провайдера WebSocket. Для получения дополнительной информации об установке и использовании пакета ознакомьтесь с официальной документацией.

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

#Reverb

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

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

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

import Echo from 'laravel-echo';

import Pusher from 'pusher-js';
window.Pusher = Pusher;

window.Echo = new Echo({
    broadcaster: 'reverb',
    key: import.meta.env.VITE_REVERB_APP_KEY,
    wsHost: import.meta.env.VITE_REVERB_HOST,
    wsPort: import.meta.env.VITE_REVERB_PORT,
    wssPort: import.meta.env.VITE_REVERB_PORT,
    forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
    enabledTransports: ['ws', 'wss'],
});

Далее скомпилируйте ассеты вашего приложения:

npm run build
Внимание

Транслятор Laravel Echo reverb требует laravel-echo версии v1.16.0 и выше.

#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';
import Pusher from 'pusher-js';

window.Pusher = Pusher;

window.Echo = new Echo({
    broadcaster: 'pusher',
    key: import.meta.env.VITE_PUSHER_APP_KEY,
    cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER,
    forceTLS: true
});

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

npm run build
Примечание

Чтобы узнать больше о компиляции JavaScript-ассетов вашего приложения, ознакомьтесь с документацией по Vite.

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

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

import Echo from 'laravel-echo';
import Pusher from 'pusher-js';

const options = {
    broadcaster: 'pusher',
    key: 'your-pusher-channels-key'
}

window.Echo = new Echo({
    ...options,
    client: new Pusher(options.key, options)
});

#Ably

Примечание

В документации ниже описывается использование Ably в режиме совместимости с Pusher. Однако команда Ably рекомендует и поддерживает драйвер и клиент Echo, которые используют уникальные возможности Ably. Для дополнительной информации об использовании драйверов Ably ознакомьтесь с документацией Ably Laravel broadcaster.

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

Возможно, вы задаётесь вопросом, зачем устанавливать JavaScript-библиотеку pusher-js, если мы используем 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';
import Pusher from 'pusher-js';

window.Pusher = Pusher;

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

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

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

npm run dev
Примечание

Чтобы узнать больше о компиляции JavaScript-ассетов вашего приложения, ознакомьтесь с документацией по Vite.

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

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

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

Примечание

Если вы хотите изучить открытые альтернативы Pusher, ознакомьтесь с разделом открытые альтернативы.

#Использование примерного приложения

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

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

use App\Events\OrderShipmentStatusUpdated;

OrderShipmentStatusUpdated::dispatch($order);

#Интерфейс ShouldBroadcast

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

<?php

namespace App\Events;

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

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

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

use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\PrivateChannel;

/**
 * Получить канал, на котором должно транслироваться событие.
 */
public function broadcastOn(): Channel
{
    return new PrivateChannel('orders.'.$this->order->id);
}

Если вы хотите транслировать событие на нескольких каналах, можно вернуть array:

use Illuminate\Broadcasting\PrivateChannel;

/**
 * Получить каналы, на которых должно транслироваться событие.
 *
 * @return array<int, \Illuminate\Broadcasting\Channel>
 */
public function broadcastOn(): array
{
    return [
        new PrivateChannel('orders.'.$this->order->id),
        // ...
    ];
}

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

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

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

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

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

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

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

Далее остаётся только прослушать событие в 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 представляют публичные каналы, на которые может подписаться любой пользователь, а PrivateChannel и PresenceChannel — приватные каналы, требующие авторизации канала:

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

    /**
     * Создать новый экземпляр события.
     */
    public function __construct(
        public User $user,
    ) {}

    /**
     * Получить каналы, на которых должно транслироваться событие.
     *
     * @return array<int, \Illuminate\Broadcasting\Channel>
     */
    public function broadcastOn(): array
    {
        return [
            new PrivateChannel('user.'.$this->user->id),
        ];
    }
}

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

#Имя трансляции

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

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

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

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

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

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

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

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

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

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

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

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

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

Альтернативно, вы можете настроить имя очереди, определив метод broadcastQueue в событии:

/**
 * Имя очереди, в которую помещается задача трансляции.
 */
public function broadcastQueue(): string
{
    return 'default';
}

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

<?php

use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;

class OrderShipmentStatusUpdated implements ShouldBroadcastNow
{
    // ...
}

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

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

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

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

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

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

<?php

namespace App\Events;

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

class ServerCreated implements ShouldBroadcast, ShouldDispatchAfterCommit
{
    use SerializesModels;
}
Примечание

Чтобы узнать больше о способах обхода этих проблем, ознакомьтесь с документацией по очередям и транзакциям базы данных.

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

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

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

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

Broadcast::routes();

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

Broadcast::routes($attributes);

#Настройка конечной точки авторизации

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

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

#Настройка запроса авторизации

Вы можете настроить, как Laravel Echo выполняет запросы авторизации, предоставив собственный авторизатор при инициализации Echo:

window.Echo = new Echo({
    // ...
    authorizer: (channel, options) => {
        return {
            authorize: (socketId, callback) => {
                axios.post('/api/broadcasting/auth', {
                    socket_id: socketId,
                    channel_name: channel.name
                })
                .then(response => {
                    callback(null, response.data);
                })
                .catch(error => {
                    callback(error);
                });
            }
        };
    },
})

#Определение обратных вызовов авторизации

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

use App\Models\User;

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

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

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

Вы можете просмотреть список обратных вызовов авторизации трансляций вашего приложения с помощью Artisan-команды channel:list:

php artisan channel:list

#Привязка модели в обратных вызовах авторизации

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

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

Broadcast::channel('orders.{order}', function (User $user, Order $order) {
    return $user->id === $order->user_id;
});
Внимание

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

#Аутентификация в обратных вызовах авторизации

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

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

#Определение классов каналов

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

php artisan make:channel OrderChannel

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

use App\Broadcasting\OrderChannel;

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

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

<?php

namespace App\Broadcasting;

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

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

    /**
     * Аутентифицировать доступ пользователя к каналу.
     */
    public function join(User $user, Order $order): array|bool
    {
        return $user->id === $order->user_id;
    }
}
Примечание

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

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

После того как вы определили событие и пометили его интерфейсом ShouldBroadcast, достаточно вызвать метод dispatch этого события. Диспетчер событий заметит, что событие помечено интерфейсом 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.

#Настройка

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

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

var socketId = Echo.socketId();

#Настройка соединения

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

use App\Events\OrderShipmentStatusUpdated;

broadcast(new OrderShipmentStatusUpdated($update))->via('pusher');

В качестве альтернативы вы можете указать соединение трансляции события, вызвав метод broadcastVia в конструкторе события. Однако перед этим убедитесь, что класс события использует трейд InteractsWithBroadcasting:

<?php

namespace App\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithBroadcasting;
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
{
    use InteractsWithBroadcasting;

    /**
     * Создать новый экземпляр события.
     */
    public function __construct()
    {
        $this->broadcastVia('pusher');
    }
}

#Получение трансляций

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

После того как вы установили и инициализировали 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(/* ... */);

#Прекращение прослушивания событий

Если вы хотите прекратить прослушивание определённого события без покидания канала, вы можете использовать метод stopListening:

Echo.private(`orders.${this.order.id}`)
    .stopListening('OrderShipmentStatusUpdated')

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

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

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

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

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

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

Вы могли заметить в приведённых выше примерах, что мы не указывали полный namespace 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) => {
        // ...
    });

#Presence-каналы

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

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

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

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

use App\Models\User;

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

#Присоединение к presence-каналам

Для присоединения к presence-каналу используйте метод join Echo. Метод join возвращает реализацию PresenceChannel, которая, помимо метода listen, позволяет подписываться на события here, joining и leaving.

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

Обратный вызов here будет выполнен сразу после успешного присоединения к каналу и получит массив с информацией о всех других пользователях, подписанных на канал. Метод joining вызывается, когда новый пользователь присоединяется к каналу, а метод leaving — когда пользователь покидает канал. Метод error вызывается, если конечная точка аутентификации возвращает HTTP-статус, отличный от 200, или возникает проблема с разбором возвращённого JSON.

#Трансляция в presence-каналы

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

/**
 * Получить каналы, на которых должно транслироваться событие.
 *
 * @return array<int, \Illuminate\Broadcasting\Channel>
 */
public function broadcastOn(): array
{
    return [
        new PresenceChannel('chat.'.$this->message->room_id),
    ];
}

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

broadcast(new NewMessage($message));

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

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

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

#Трансляция моделей

Внимание

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

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

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

Для начала ваша модель Eloquent должна использовать трейд Illuminate\Database\Eloquent\BroadcastsEvents. Кроме того, модель должна определить метод broadcastOn, который возвращает массив каналов, на которых должны транслироваться события модели:

<?php

namespace App\Models;

use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Database\Eloquent\BroadcastsEvents;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class Post extends Model
{
    use BroadcastsEvents, HasFactory;

    /**
     * Получить пользователя, которому принадлежит пост.
     */
    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }

    /**
     * Получить каналы, на которых должны транслироваться события модели.
     *
     * @return array<int, \Illuminate\Broadcasting\Channel|\Illuminate\Database\Eloquent\Model>
     */
    public function broadcastOn(string $event): array
    {
        return [$this, $this->user];
    }
}

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

Кроме того, вы могли заметить, что метод broadcastOn принимает строковый аргумент $event. Этот аргумент содержит тип произошедшего события модели и может принимать значения created, updated, deleted, trashed или restored. Анализируя значение этой переменной, вы можете определить, на какие каналы (если на какие-либо) модель должна транслировать событие для конкретного действия:

/**
 * Получить каналы, на которых должны транслироваться события модели.
 *
 * @return array<string, array<int, \Illuminate\Broadcasting\Channel|\Illuminate\Database\Eloquent\Model>>
 */
public function broadcastOn(string $event): array
{
    return match ($event) {
        'deleted' => [],
        default => [$this, $this->user],
    };
}

#Настройка создания событий трансляции модели

Иногда может потребоваться настроить, как Laravel создаёт базовое событие трансляции модели. Это можно сделать, определив метод newBroadcastableEvent в вашей модели Eloquent. Этот метод должен возвращать экземпляр Illuminate\Database\Eloquent\BroadcastableModelEventOccurred:

use Illuminate\Database\Eloquent\BroadcastableModelEventOccurred;

/**
 * Создать новое событие трансляции модели для модели.
 */
protected function newBroadcastableEvent(string $event): BroadcastableModelEventOccurred
{
    return (new BroadcastableModelEventOccurred(
        $this, $event
    ))->dontBroadcastToCurrentUser();
}

#Конвенции трансляции моделей

#Конвенции каналов

Как вы могли заметить, метод broadcastOn в примере модели выше не возвращал экземпляры Channel. Вместо этого возвращались экземпляры моделей Eloquent. Если метод broadcastOn вашей модели возвращает экземпляр модели Eloquent (или содержит его в возвращаемом массиве), Laravel автоматически создаст экземпляр приватного канала для модели, используя имя класса модели и её первичный ключ в качестве имени канала.

Таким образом, модель App\Models\User с id равным 1 будет преобразована в экземпляр Illuminate\Broadcasting\PrivateChannel с именем App.Models.User.1. Конечно, помимо возврата экземпляров моделей Eloquent из метода broadcastOn, вы можете возвращать полноценные экземпляры Channel, чтобы полностью контролировать имена каналов модели:

use Illuminate\Broadcasting\PrivateChannel;

/**
 * Получить каналы, на которых должны транслироваться события модели.
 *
 * @return array<int, \Illuminate\Broadcasting\Channel>
 */
public function broadcastOn(string $event): array
{
    return [
        new PrivateChannel('user.'.$this->id)
    ];
}

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

return [new Channel($this->user)];

Если вам нужно определить имя канала модели, вы можете вызвать метод broadcastChannel у любого экземпляра модели. Например, этот метод вернёт строку App.Models.User.1 для модели App\Models\User с id равным 1:

$user->broadcastChannel()

#Конвенции событий

Поскольку события трансляции моделей не связаны с «реальными» событиями в директории App\Events вашего приложения, им присваиваются имя и полезная нагрузка на основе конвенций. Конвенция Laravel — транслировать событие, используя имя класса модели (без пространства имён) и имя события модели, вызвавшего трансляцию.

Например, обновление модели App\Models\Post будет транслировать событие в ваше клиентское приложение как PostUpdated с такой полезной нагрузкой:

{
    "model": {
        "id": 1,
        "title": "My first post"
        ...
    },
    ...
    "socket": "someSocketId",
}

Удаление модели App\Models\User будет транслировать событие с именем UserDeleted.

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

/**
 * Имя трансляции события модели.
 */
public function broadcastAs(string $event): string|null
{
    return match ($event) {
        'created' => 'post.created',
        default => null,
    };
}

/**
 * Получить данные для трансляции модели.
 *
 * @return array<string, mixed>
 */
public function broadcastWith(string $event): array
{
    return match ($event) {
        'created' => ['title' => $this->title],
        default => ['model' => $this],
    };
}

#Прослушивание трансляций моделей

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

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

После того как вы получите экземпляр канала, вы можете использовать метод listen для прослушивания конкретного события. Поскольку события трансляции модели не связаны с «реальным» событием в каталоге App\Events вашего приложения, имя события должно начинаться с префикса . для указания, что оно не принадлежит определённому пространству имён. Каждое событие трансляции модели имеет свойство model, которое содержит все свойства модели, доступные для трансляции:

Echo.private(`App.Models.User.${this.user.id}`)
    .listen('.PostUpdated', (e) => {
        console.log(e.model);
    });

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

Примечание

При использовании 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.