Бродкастинг
Вступ
У багатьох сучасних вебзастосунках WebSocket використовують, щоб будувати інтерфейси, які оновлюються в реальному часі. Коли на сервері оновлюються якісь дані, через WebSocket-з'єднання зазвичай надсилається повідомлення, яке обробляє клієнт. WebSocket - ефективніша альтернатива постійному опитуванню сервера на предмет змін, які мають відобразитися в інтерфейсі.
Наприклад, уявіть, що ваш застосунок уміє експортувати дані користувача у CSV-файл і надсилати його поштою. Проте створення цього CSV-файлу займає кілька хвилин, тож ви створюєте й надсилаєте CSV у завданні в черзі. Коли CSV створено й надіслано користувачеві, ми можемо скористатися бродкастингом подій, щоб диспетчеризувати подію App\Events\UserDataExported, яку отримає JavaScript нашого застосунку. Отримавши подію, ми можемо показати користувачеві повідомлення, що його CSV надіслано поштою, - і йому не доведеться оновлювати сторінку.
Щоб допомогти вам будувати такі можливості, Laravel спрощує «бродкастинг» серверних подій Laravel через WebSocket-з'єднання. Бродкастинг подій Laravel дозволяє мати спільні імена подій і дані між серверним застосунком Laravel і клієнтським застосунком на JavaScript.
Основні ідеї бродкастингу прості: на фронтенді клієнти підключаються до іменованих каналів, а ваш застосунок Laravel на бекенді надсилає події в ці канали. Ці події можуть містити будь-які додаткові дані, які ви хочете зробити доступними на фронтенді.
Підтримувані драйвери
За замовчуванням Laravel містить три серверні драйвери бродкастингу на вибір: Laravel Reverb, Pusher Channels та Ably.
Перш ніж занурюватися в бродкастинг подій, обов'язково прочитайте документацію Laravel про події та слухачів.
Швидкий старт
За замовчуванням у нових застосунках Laravel бродкастинг вимкнено. Увімкнути його можна командою Artisan install:broadcasting:
php artisan install:broadcasting
Команда install:broadcasting запитає, який сервіс бродкастингу подій ви хочете використовувати. Крім того, вона створить файл конфігурації config/broadcasting.php і файл routes/channels.php, де ви можете реєструвати маршрути та колбеки авторизації бродкастингу вашого застосунку.
Laravel «з коробки» підтримує кілька драйверів бродкастингу: Laravel Reverb, Pusher Channels, Ably, а також драйвер log для локальної розробки й налагодження. Крім того, є драйвер null, який дозволяє вимкнути бродкастинг під час тестування. Приклад конфігурації для кожного з цих драйверів є у файлі config/broadcasting.php.
Уся конфігурація бродкастингу подій вашого застосунку зберігається у файлі config/broadcasting.php. Не переймайтеся, якщо цього файлу у вашому застосунку немає, - його буде створено, коли ви виконаєте команду Artisan install:broadcasting.
Наступні кроки
Щойно ви увімкнули бродкастинг подій, можна вивчати опис подій для бродкастингу і прослуховування подій. Якщо ви користуєтеся стартовими наборами Laravel для React, Vue чи Svelte, слухати події можна через хук useEcho з Echo.
Перш ніж надсилати будь-які події, вам слід налаштувати й запустити воркер черги. Увесь бродкастинг подій відбувається через завдання в черзі, щоб час відповіді вашого застосунку суттєво не страждав від надсилання подій.
Встановлення на боці сервера
Щоб почати користуватися бродкастингом подій у Laravel, нам потрібно дещо налаштувати в застосунку Laravel, а також встановити кілька пакетів.
Бродкастинг подій виконує серверний драйвер бродкастингу, який надсилає ваші події Laravel так, щоб Laravel Echo (бібліотека на JavaScript) могла отримати їх у браузері. Не хвилюйтеся - ми пройдемо кожен крок встановлення по черзі.
Reverb
Щоб швидко увімкнути підтримку бродкастингу в Laravel із Reverb як бродкастером подій, виконайте команду Artisan install:broadcasting з опцією --reverb. Ця команда встановить потрібні Reverb пакети Composer і NPM та оновить файл .env вашого застосунку відповідними змінними:
php artisan install:broadcasting --reverb
Встановлення вручну
Під час виконання команди install:broadcasting вам запропонують встановити Laravel Reverb. Звісно, ви можете встановити Reverb і вручну через менеджер пакетів Composer:
composer require laravel/reverb
Щойно пакет встановлено, ви можете виконати команду встановлення Reverb, щоб опублікувати конфігурацію, додати потрібні Reverb змінні середовища й увімкнути бродкастинг подій у застосунку:
php artisan reverb:install
Детальні інструкції зі встановлення та використання Reverb ви знайдете в документації Reverb.
Pusher Channels
Щоб швидко увімкнути підтримку бродкастингу в Laravel із Pusher як бродкастером подій, виконайте команду Artisan install:broadcasting з опцією --pusher. Ця команда запитає ваші облікові дані Pusher, встановить PHP- та JavaScript-SDK Pusher і оновить файл .env вашого застосунку відповідними змінними:
php artisan install:broadcasting --pusher
Встановлення вручну
Щоб встановити підтримку Pusher вручну, встановіть PHP SDK Pusher Channels через менеджер пакетів Composer:
composer require pusher/pusher-php-server
Далі налаштуйте облікові дані Pusher Channels у файлі конфігурації config/broadcasting.php. Приклад конфігурації Pusher Channels уже є в цьому файлі, тож ви можете швидко вказати свої ключ, секрет та ID застосунку. Зазвичай облікові дані Pusher Channels налаштовують у файлі .env вашого застосунку:
PUSHER_APP_ID="your-pusher-app-id"
PUSHER_APP_KEY="your-pusher-key"
PUSHER_APP_SECRET="your-pusher-secret"
PUSHER_HOST=
PUSHER_PORT=443
PUSHER_SCHEME="https"
PUSHER_APP_CLUSTER="mt1"
Конфігурація pusher у файлі config/broadcasting.php також дозволяє вказати додаткові options, які підтримує Channels, - наприклад, кластер.
Далі задайте змінній середовища BROADCAST_CONNECTION значення pusher у файлі .env вашого застосунку:
BROADCAST_CONNECTION=pusher
Нарешті, ви готові встановити й налаштувати Laravel Echo, яка отримуватиме події бродкастингу на боці клієнта.
Ably
Документація нижче описує використання Ably в режимі «сумісності з Pusher». Проте команда Ably рекомендує й підтримує власні бродкастер та клієнт Echo, які вміють користуватися унікальними можливостями Ably. Докладніше про драйвери від Ably читайте в документації бродкастера Ably для Laravel.
Щоб швидко увімкнути підтримку бродкастингу в Laravel з Ably як бродкастером подій, виконайте команду Artisan install:broadcasting з опцією --ably. Ця команда запитає ваші облікові дані Ably, встановить PHP- та JavaScript-SDK Ably і оновить файл .env вашого застосунку відповідними змінними:
php artisan install:broadcasting --ably
Перш ніж продовжувати, увімкніть підтримку протоколу Pusher у налаштуваннях вашого застосунку Ably. Зробити це можна в розділі «Protocol Adapter Settings» панелі налаштувань застосунку Ably.
Встановлення вручну
Щоб встановити підтримку Ably вручну, встановіть PHP SDK Ably через менеджер пакетів Composer:
composer require ably/ably-php
Далі налаштуйте облікові дані Ably у файлі конфігурації config/broadcasting.php. Приклад конфігурації Ably уже є в цьому файлі, тож ви можете швидко вказати свій ключ. Зазвичай це значення задають через змінну середовища ABLY_KEY:
ABLY_KEY=your-ably-key
Далі задайте змінній середовища BROADCAST_CONNECTION значення ably у файлі .env вашого застосунку:
BROADCAST_CONNECTION=ably
Нарешті, ви готові встановити й налаштувати Laravel Echo, яка отримуватиме події бродкастингу на боці клієнта.
Встановлення на боці клієнта
Reverb
Laravel Echo - це бібліотека на JavaScript, яка робить підписку на канали й прослуховування подій, надісланих вашим серверним драйвером бродкастингу, безболісними.
Коли ви встановлюєте Laravel Reverb командою Artisan install:broadcasting, каркас і конфігурацію Reverb та Echo буде додано до вашого застосунку автоматично. Проте, якщо ви хочете налаштувати Laravel Echo вручну, скористайтеся інструкціями нижче.
Встановлення вручну
Щоб налаштувати Laravel Echo для фронтенду вашого застосунку вручну, спершу встановіть пакет pusher-js, оскільки Reverb використовує протокол Pusher для WebSocket-підписок, каналів і повідомлень:
npm install --save-dev laravel-echo pusher-js
Щойно Echo встановлено, ви можете створити свіжий екземпляр Echo у JavaScript вашого застосунку. Чудове місце для цього - кінець файлу resources/js/app.js, який входить до складу фреймворку Laravel:
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 ?? 80,
wssPort: import.meta.env.VITE_REVERB_PORT ?? 443,
forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
enabledTransports: ['ws', 'wss'],
});
import { configureEcho } from "@laravel/echo-react";
configureEcho({
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'],
});
import { configureEcho } from "@laravel/echo-vue";
configureEcho({
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'],
});
import { configureEcho } from "@laravel/echo-svelte";
configureEcho({
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
Бродкастер
reverbдля Laravel Echo потребує laravel-echo v1.16.0+.
Pusher Channels
Laravel Echo - це бібліотека на JavaScript, яка робить підписку на канали й прослуховування подій, надісланих вашим серверним драйвером бродкастингу, безболісними.
Коли ви встановлюєте підтримку бродкастингу командою Artisan install:broadcasting --pusher, каркас і конфігурацію Pusher та Echo буде додано до вашого застосунку автоматично. Проте, якщо ви хочете налаштувати Laravel Echo вручну, скористайтеся інструкціями нижче.
Встановлення вручну
Щоб налаштувати Laravel Echo для фронтенду вашого застосунку вручну, спершу встановіть пакети laravel-echo та pusher-js, які використовують протокол Pusher для WebSocket-підписок, каналів і повідомлень:
npm install --save-dev laravel-echo pusher-js
Щойно Echo встановлено, ви можете створити свіжий екземпляр Echo у файлі resources/js/app.js вашого застосунку:
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
});
import { configureEcho } from "@laravel/echo-react";
configureEcho({
broadcaster: "pusher",
// key: import.meta.env.VITE_PUSHER_APP_KEY,
// cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER,
// forceTLS: true,
// wsHost: import.meta.env.VITE_PUSHER_HOST,
// wsPort: import.meta.env.VITE_PUSHER_PORT,
// wssPort: import.meta.env.VITE_PUSHER_PORT,
// enabledTransports: ["ws", "wss"],
});
import { configureEcho } from "@laravel/echo-vue";
configureEcho({
broadcaster: "pusher",
// key: import.meta.env.VITE_PUSHER_APP_KEY,
// cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER,
// forceTLS: true,
// wsHost: import.meta.env.VITE_PUSHER_HOST,
// wsPort: import.meta.env.VITE_PUSHER_PORT,
// wssPort: import.meta.env.VITE_PUSHER_PORT,
// enabledTransports: ["ws", "wss"],
});
import { configureEcho } from "@laravel/echo-svelte";
configureEcho({
broadcaster: "pusher",
// key: import.meta.env.VITE_PUSHER_APP_KEY,
// cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER,
// forceTLS: true,
// wsHost: import.meta.env.VITE_PUSHER_HOST,
// wsPort: import.meta.env.VITE_PUSHER_PORT,
// wssPort: import.meta.env.VITE_PUSHER_PORT,
// enabledTransports: ["ws", "wss"],
});
Далі задайте відповідні значення змінних середовища Pusher у файлі .env вашого застосунку. Якщо цих змінних у файлі .env ще немає, додайте їх:
PUSHER_APP_ID="your-pusher-app-id"
PUSHER_APP_KEY="your-pusher-key"
PUSHER_APP_SECRET="your-pusher-secret"
PUSHER_HOST=
PUSHER_PORT=443
PUSHER_SCHEME="https"
PUSHER_APP_CLUSTER="mt1"
VITE_APP_NAME="${APP_NAME}"
VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
VITE_PUSHER_HOST="${PUSHER_HOST}"
VITE_PUSHER_PORT="${PUSHER_PORT}"
VITE_PUSHER_SCHEME="${PUSHER_SCHEME}"
VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
Щойно ви скоригували конфігурацію 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: import.meta.env.VITE_PUSHER_APP_KEY
}
window.Echo = new Echo({
...options,
client: new Pusher(options.key, options)
});
Ably
Документація нижче описує використання Ably в режимі «сумісності з Pusher». Проте команда Ably рекомендує й підтримує власні бродкастер та клієнт Echo, які вміють користуватися унікальними можливостями Ably. Докладніше про драйвери від Ably читайте в документації бродкастера Ably для Laravel.
Laravel Echo - це бібліотека на JavaScript, яка робить підписку на канали й прослуховування подій, надісланих вашим серверним драйвером бродкастингу, безболісними.
Коли ви встановлюєте підтримку бродкастингу командою Artisan install:broadcasting --ably, каркас і конфігурацію Ably та Echo буде додано до вашого застосунку автоматично. Проте, якщо ви хочете налаштувати Laravel Echo вручну, скористайтеся інструкціями нижче.
Встановлення вручну
Щоб налаштувати Laravel Echo для фронтенду вашого застосунку вручну, спершу встановіть пакети laravel-echo та pusher-js, які використовують протокол Pusher для WebSocket-підписок, каналів і повідомлень:
npm install --save-dev laravel-echo pusher-js
Перш ніж продовжувати, увімкніть підтримку протоколу Pusher у налаштуваннях вашого застосунку Ably. Зробити це можна в розділі «Protocol Adapter Settings» панелі налаштувань застосунку Ably.
Щойно Echo встановлено, ви можете створити свіжий екземпляр Echo у файлі resources/js/app.js вашого застосунку:
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,
});
import { configureEcho } from "@laravel/echo-react";
configureEcho({
broadcaster: "ably",
// key: import.meta.env.VITE_ABLY_PUBLIC_KEY,
// wsHost: "realtime-pusher.ably.io",
// wsPort: 443,
// disableStats: true,
// encrypted: true,
});
import { configureEcho } from "@laravel/echo-vue";
configureEcho({
broadcaster: "ably",
// key: import.meta.env.VITE_ABLY_PUBLIC_KEY,
// wsHost: "realtime-pusher.ably.io",
// wsPort: 443,
// disableStats: true,
// encrypted: true,
});
import { configureEcho } from "@laravel/echo-svelte";
configureEcho({
broadcaster: "ably",
// 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, використовуючи драйверний підхід до WebSocket. Наразі Laravel постачається з драйверами Laravel Reverb, Pusher Channels та Ably. Події легко спожити на боці клієнта за допомогою JavaScript-пакета Laravel Echo.
Події надсилаються через «канали», які можуть бути публічними або приватними. Будь-який відвідувач вашого застосунку може підписатися на публічний канал без автентифікації чи авторизації; натомість, щоб підписатися на приватний канал, користувач має бути автентифікований і авторизований слухати цей канал.
На прикладі застосунку
Перш ніж заглиблюватися в кожен компонент бродкастингу подій, розгляньмо все з висоти пташиного польоту на прикладі інтернет-магазину.
Припустімо, у нашому застосунку є сторінка, на якій користувачі бачать статус доставки своїх замовлень. Припустімо також, що коли застосунок обробляє оновлення статусу доставки, спрацьовує подія 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
{
/**
* The order instance.
*
* @var \App\Models\Order
*/
public $order;
}
Інтерфейс ShouldBroadcast вимагає, щоб наша подія описала метод broadcastOn. Цей метод відповідає за повернення каналів, у які має надсилатися подія. Порожня заготовка цього методу вже є у згенерованих класах подій, тож нам залишається лише заповнити її. Ми хочемо, щоб оновлення статусу бачив лише автор замовлення, тому надсилатимемо подію в приватний канал, прив'язаний до замовлення:
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\PrivateChannel;
/**
* Get the channel the event should broadcast on.
*/
public function broadcastOn(): Channel
{
return new PrivateChannel('orders.'.$this->order->id);
}
Якщо ви хочете надсилати подію в кілька каналів, поверніть замість цього array:
use Illuminate\Broadcasting\PrivateChannel;
/**
* Get the channels the event should broadcast on.
*
* @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}, щоб позначити, що частина імені каналу з «ID» є підстановкою.
Прослуховування бродкастів подій
Далі лишається тільки послухати подію в нашому застосунку на JavaScript. Зробити це можна за допомогою Laravel Echo. Вбудовані в Laravel Echo хуки для React, Vue та Svelte роблять старт простим, і за замовчуванням усі публічні властивості події потраплять до надісланої події:
import { useEcho } from "@laravel/echo-react";
useEcho(
`orders.${orderId}`,
"OrderShipmentStatusUpdated",
(e) => {
console.log(e.order);
},
);
<script setup lang="ts">
import { useEcho } from "@laravel/echo-vue";
useEcho(
`orders.${orderId}`,
"OrderShipmentStatusUpdated",
(e) => {
console.log(e.order);
},
);
</script>
<script>
import { useEcho } from "@laravel/echo-svelte";
useEcho(
`orders.${orderId}`,
"OrderShipmentStatusUpdated",
(e) => {
console.log(e.order);
},
);
</script>
Опис подій для бродкастингу
Щоб повідомити 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;
/**
* Create a new event instance.
*/
public function __construct(
public User $user,
) {}
/**
* Get the channels the event should broadcast on.
*
* @return array<int, \Illuminate\Broadcasting\Channel>
*/
public function broadcastOn(): array
{
return [
new PrivateChannel('user.'.$this->user->id),
];
}
}
Реалізувавши інтерфейс ShouldBroadcast, вам залишається лише запустити подію як зазвичай. Щойно подію запущено, завдання в черзі автоматично надішле її через вказаний драйвер бродкастингу.
Ім'я бродкасту
За замовчуванням Laravel надсилає подію під іменем її класу. Проте ви можете змінити ім'я бродкасту, описавши в події метод broadcastAs:
/**
* The event's broadcast name.
*/
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. Цей метод має повернути масив даних, які ви хочете надіслати як дані події:
/**
* Get the data to broadcast.
*
* @return array<string, mixed>
*/
public function broadcastWith(): array
{
return ['id' => $this->user->id];
}
Черга бродкасту
За замовчуванням кожна подія бродкастингу потрапляє до черги за замовчуванням для підключення черги за замовчуванням, вказаного у файлі конфігурації queue.php. Ви можете змінити підключення й ім'я черги, які використовує бродкастер, за допомогою атрибутів Connection та Queue у класі події:
use Illuminate\Queue\Attributes\Connection;
use Illuminate\Queue\Attributes\Queue;
#[Connection('redis')]
#[Queue('default')]
class ServerCreated implements ShouldBroadcast
{
// ...
}
Як варіант, ви можете змінити ім'я черги, описавши в події метод broadcastQueue:
/**
* The name of the queue on which to place the broadcasting job.
*/
public function broadcastQueue(): string
{
return 'default';
}
Якщо ви хочете надсилати подію через чергу sync замість драйвера черги за замовчуванням, реалізуйте інтерфейс ShouldBroadcastNow замість ShouldBroadcast:
<?php
namespace App\Events;
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
class OrderShipmentStatusUpdated implements ShouldBroadcastNow
{
// ...
}
Умови бродкасту
Інколи потрібно надсилати подію лише за певної умови. Описати такі умови можна, додавши до класу події метод broadcastWhen:
/**
* Determine if this event should broadcast.
*/
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 намагається автоматично зареєструвати маршрут /broadcasting/auth для обробки запитів авторизації. Якщо Laravel не вдасться зареєструвати ці маршрути автоматично, ви можете зареєструвати їх вручну у файлі /bootstrap/app.php вашого застосунку:
->withRouting(
web: __DIR__.'/../routes/web.php',
channels: __DIR__.'/../routes/channels.php',
health: '/up',
)
Опис колбеків авторизації
Далі нам потрібно описати логіку, яка визначатиме, чи може поточний автентифікований користувач слухати певний канал. Це робиться у файлі routes/channels.php, який створює команда Artisan install:broadcasting. У цьому файлі ви можете реєструвати колбеки авторизації каналів методом 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-маршрутах, прив'язка моделей у каналах не підтримує автоматичне скопування неявної прив'язки моделей. Утім, це рідко стає проблемою, бо більшість каналів можна скопувати за унікальним первинним ключем однієї моделі.
Автентифікація в колбеках авторизації
Приватні канали та канали присутності автентифікують поточного користувача через гард автентифікації за замовчуванням вашого застосунку. Якщо користувач не автентифікований, авторизацію каналу буде автоматично відхилено, а колбек авторизації ніколи не виконається. Проте за потреби ви можете призначити кілька власних гардів, які мають автентифікувати вхідний запит:
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
{
/**
* Create a new channel instance.
*/
public function __construct() {}
/**
* Authenticate the user's access to the channel.
*/
public function join(User $user, Order $order): array|bool
{
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, який скаже бродкастеру не надсилати подію поточному користувачеві.
Щоб викликати метод
toOthers, ваша подія має використовувати трейтIlluminate\Broadcasting\InteractsWithSockets.
Конфігурація
Коли ви ініціалізуєте екземпляр Laravel Echo, з'єднанню призначається ID сокета. Якщо ви користуєтеся глобальним екземпляром Axios для HTTP-запитів із застосунку на JavaScript, ID сокета автоматично додається до кожного вихідного запиту заголовком X-Socket-ID. Тоді, коли ви викликаєте метод toOthers, Laravel дістане ID сокета із заголовка й скаже бродкастеру не надсилати подію жодному з'єднанню з цим ID сокета.
Якщо ви не користуєтеся глобальним екземпляром Axios, вам доведеться вручну налаштувати ваш застосунок на JavaScript надсилати заголовок X-Socket-ID з усіма вихідними запитами. Отримати 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;
/**
* Create a new event instance.
*/
public function __construct()
{
$this->broadcastVia('pusher');
}
}
Анонімні події
Інколи вам може захотітися надіслати просту подію на фронтенд застосунку, не створюючи окремого класу події. Для цього фасад Broadcast дозволяє надсилати «анонімні події»:
Broadcast::on('orders.'.$order->id)->send();
Приклад вище надішле таку подію:
{
"event": "AnonymousEvent",
"data": "[]",
"channel": "orders.1"
}
Методами as і with ви можете змінити ім'я та дані події:
Broadcast::on('orders.'.$order->id)
->as('OrderPlaced')
->with($order)
->send();
Приклад вище надішле подію на кшталт такої:
{
"event": "OrderPlaced",
"data": "{ id: 1, total: 100 }",
"channel": "orders.1"
}
Якщо ви хочете надіслати анонімну подію в приватний канал або канал присутності, скористайтеся методами private та presence:
Broadcast::private('orders.'.$order->id)->send();
Broadcast::presence('channels.'.$channel->id)->send();
Надсилання анонімної події методом send диспетчеризує подію до черги вашого застосунку на обробку. Проте, якщо ви хочете надіслати подію негайно, скористайтеся методом sendNow:
Broadcast::on('orders.'.$order->id)->sendNow();
Щоб надіслати подію всім підписникам каналу, окрім поточного автентифікованого користувача, викличте метод toOthers:
Broadcast::on('orders.'.$order->id)
->toOthers()
->send();
Убезпечення бродкастів
Коли сервер черги вашого застосунку недоступний або Laravel натрапляє на помилку під час надсилання події, викидається виняток, через який кінцевий користувач зазвичай бачить помилку застосунку. Оскільки бродкастинг подій часто є доповненням до основної функціональності застосунку, ви можете не дати цим винятками псувати користувацький досвід, - реалізуйте у своїх подіях інтерфейс ShouldRescue.
Події, які реалізують інтерфейс ShouldRescue, під час спроб бродкастингу автоматично використовують функцію-хелпер rescue Laravel. Цей хелпер ловить будь-які винятки, повідомляє про них обробнику винятків вашого застосунку для логування й дозволяє застосунку працювати далі, не перериваючи роботу користувача:
<?php
namespace App\Events;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Contracts\Broadcasting\ShouldRescue;
class ServerCreated implements ShouldBroadcast, ShouldRescue
{
// ...
}
Отримання бродкастів
Прослуховування подій
Щойно ви встановили та створили екземпляр 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}`);
Якщо ви хочете вийти з каналу разом із пов'язаними з ним приватним каналом і каналом присутності, викличте метод 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) => {
// ...
});
Використання React, Vue чи Svelte
Laravel Echo містить хуки для React, Vue та Svelte, які роблять прослуховування подій безболісним. Для початку викличте хук useEcho, який слухає приватні події. Хук useEcho автоматично виходить з каналів, коли компонент, який його використовує, демонтується:
import { useEcho } from "@laravel/echo-react";
useEcho(
`orders.${orderId}`,
"OrderShipmentStatusUpdated",
(e) => {
console.log(e.order);
},
);
<script setup lang="ts">
import { useEcho } from "@laravel/echo-vue";
useEcho(
`orders.${orderId}`,
"OrderShipmentStatusUpdated",
(e) => {
console.log(e.order);
},
);
</script>
<script>
import { useEcho } from "@laravel/echo-svelte";
useEcho(
`orders.${orderId}`,
"OrderShipmentStatusUpdated",
(e) => {
console.log(e.order);
},
);
</script>
Ви можете слухати кілька подій, передавши до useEcho масив подій:
useEcho(
`orders.${orderId}`,
["OrderShipmentStatusUpdated", "OrderShipped"],
(e) => {
console.log(e.order);
},
);
Ви також можете описати форму даних події бродкасту, отримавши кращу типобезпеку й зручність редагування:
type OrderData = {
order: {
id: number;
user: {
id: number;
name: string;
};
created_at: string;
};
};
useEcho<OrderData>(`orders.${orderId}`, "OrderShipmentStatusUpdated", (e) => {
console.log(e.order.id);
console.log(e.order.user.id);
});
Хук useEcho автоматично виходить з каналів, коли компонент, який його використовує, демонтується; проте за потреби ви можете скористатися поверненими функціями, щоб програмно зупиняти / поновлювати прослуховування каналів вручну:
import { useEcho } from "@laravel/echo-react";
const { leaveChannel, leave, stopListening, listen } = useEcho(
`orders.${orderId}`,
"OrderShipmentStatusUpdated",
(e) => {
console.log(e.order);
},
);
// Stop listening without leaving channel...
stopListening();
// Start listening again...
listen();
// Leave channel...
leaveChannel();
// Leave a channel and also its associated private and presence channels...
leave();
<script setup lang="ts">
import { useEcho } from "@laravel/echo-vue";
const { leaveChannel, leave, stopListening, listen } = useEcho(
`orders.${orderId}`,
"OrderShipmentStatusUpdated",
(e) => {
console.log(e.order);
},
);
// Stop listening without leaving channel...
stopListening();
// Start listening again...
listen();
// Leave channel...
leaveChannel();
// Leave a channel and also its associated private and presence channels...
leave();
</script>
<script>
import { useEcho } from "@laravel/echo-svelte";
const { leaveChannel, leave, stopListening, listen } = useEcho(
`orders.${orderId}`,
"OrderShipmentStatusUpdated",
(e) => {
console.log(e.order);
},
);
// Stop listening without leaving channel...
stopListening();
// Start listening again...
listen();
// Leave channel...
leaveChannel();
// Leave a channel and also its associated private and presence channels...
leave();
</script>
Підключення до публічних каналів
Щоб підключитися до публічного каналу, скористайтеся хуком useEchoPublic:
import { useEchoPublic } from "@laravel/echo-react";
useEchoPublic("posts", "PostPublished", (e) => {
console.log(e.post);
});
<script setup lang="ts">
import { useEchoPublic } from "@laravel/echo-vue";
useEchoPublic("posts", "PostPublished", (e) => {
console.log(e.post);
});
</script>
<script>
import { useEchoPublic } from "@laravel/echo-svelte";
useEchoPublic("posts", "PostPublished", (e) => {
console.log(e.post);
});
</script>
Підключення до каналів присутності
Щоб підключитися до каналу присутності, скористайтеся хуком useEchoPresence:
import { useEchoPresence } from "@laravel/echo-react";
useEchoPresence("posts", "PostPublished", (e) => {
console.log(e.post);
});
<script setup lang="ts">
import { useEchoPresence } from "@laravel/echo-vue";
useEchoPresence("posts", "PostPublished", (e) => {
console.log(e.post);
});
</script>
<script>
import { useEchoPresence } from "@laravel/echo-svelte";
useEchoPresence("posts", "PostPublished", (e) => {
console.log(e.post);
});
</script>
Статус з'єднання
Отримати поточний статус WebSocket-з'єднання можна хуком useConnectionStatus, який надає реактивний статус, що автоматично оновлюється зі зміною стану з'єднання:
import { useConnectionStatus } from "@laravel/echo-react";
function ConnectionIndicator() {
const status = useConnectionStatus();
return <div>Connection: {status}</div>;
}
<script setup lang="ts">
import { useConnectionStatus } from "@laravel/echo-vue";
const status = useConnectionStatus();
</script>
<template>
<div>Connection: {{ status }}</div>
</template>
<script>
import { useConnectionStatus } from "@laravel/echo-svelte";
const status = useConnectionStatus();
</script>
<div>Connection: {status()}</div>
Можливі значення статусу:
connected- успішно підключено до WebSocket-сервера.connecting- триває початкова спроба підключення.reconnecting- триває спроба перепідключитися після розриву.disconnected- не підключено й спроб перепідключитися немає.failed- підключення не вдалося, повторів не буде.
ID сокета
Отримати поточний ID WebSocket-сокета можна хуком useSocketId, який надає реактивне значення, що автоматично оновлюється, коли з'єднання перепідключається з новим ID сокета:
import { useSocketId } from "@laravel/echo-react";
function SocketIndicator() {
const socketId = useSocketId();
return <div>Socket ID: {socketId}</div>;
}
<script setup lang="ts">
import { useSocketId } from "@laravel/echo-vue";
const socketId = useSocketId();
</script>
<template>
<div>Socket ID: {{ socketId }}</div>
</template>
<script>
import { useSocketId } from "@laravel/echo-svelte";
const socketId = useSocketId();
</script>
<div>Socket ID: {socketId()}</div>
Канали присутності
Канали присутності будуються на безпеці приватних каналів, додаючи можливість знати, хто підписаний на канал. Це спрощує створення потужних спільних можливостей - наприклад, сповіщати користувачів, що ту саму сторінку переглядає хтось іще, або показувати список учасників чату.
Авторизація каналів присутності
Усі канали присутності є також приватними, тому користувачі мають бути авторизовані для доступу до них. Проте, описуючи колбеки авторизації для каналів присутності, ви не повертаєте true, коли користувач має право приєднатися до каналу. Натомість вам слід повернути масив даних про користувача.
Дані, які повернув колбек авторизації, стануть доступні слухачам подій каналу присутності у вашому застосунку на JavaScript. Якщо користувач не має права приєднатися до каналу присутності, поверніть 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];
}
});
Приєднання до каналів присутності
Щоб приєднатися до каналу присутності, скористайтеся методом 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.
Бродкастинг у канали присутності
Канали присутності можуть отримувати події так само, як публічні чи приватні канали. На прикладі чат-кімнати ми можемо захотіти надсилати події NewMessage до каналу присутності кімнати. Для цього повернемо екземпляр PresenceChannel з методу broadcastOn події:
/**
* Get the channels the event should broadcast on.
*
* @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();
Як і для інших типів подій, слухати події, надіслані до каналів присутності, можна методом 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;
/**
* Get the user that the post belongs to.
*/
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
/**
* Get the channels that model events should broadcast on.
*
* @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. Перевіряючи значення цієї змінної, ви можете визначити, у які канали (якщо взагалі в якісь) модель має надсилати конкретну подію:
/**
* Get the channels that model events should broadcast on.
*
* @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 створює подію бродкастингу моделі під капотом. Зробити це можна, описавши в моделі Eloquent метод newBroadcastableEvent. Цей метод має повернути екземпляр Illuminate\Database\Eloquent\BroadcastableModelEventOccurred:
use Illuminate\Database\Eloquent\BroadcastableModelEventOccurred;
/**
* Create a new broadcastable model event for the model.
*/
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;
/**
* Get the channels that model events should broadcast on.
*
* @return array<int, \Illuminate\Broadcasting\Channel>
*/
public function broadcastOn(string $event): array
{
return [
new PrivateChannel('user.'.$this->id)
];
}
Якщо ви плануєте явно повертати екземпляр каналу з методу broadcastOn моделі, ви можете передати екземпляр моделі Eloquent у конструктор каналу. У такому разі Laravel скористається домовленостями щодо каналів моделей, описаними вище, щоб перетворити модель Eloquent на рядкове ім'я каналу:
return [new Channel($this->user)];
Якщо вам потрібно дізнатися ім'я каналу моделі, викличте метод broadcastChannel на будь-якому екземплярі моделі. Наприклад, для моделі App\Models\User з id 1 цей метод поверне рядок App.Models.User.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 скористається домовленостями щодо імен подій бродкастингу моделей, описаними вище:
/**
* The model event's broadcast name.
*/
public function broadcastAs(string $event): string|null
{
return match ($event) {
'created' => 'post.created',
default => null,
};
}
/**
* Get the data to broadcast for the model.
*
* @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('.UserUpdated', (e) => {
console.log(e.model);
});
Використання React, Vue чи Svelte
Якщо ви користуєтеся React, Vue чи Svelte, для зручного прослуховування бродкастів моделей скористайтеся хуком useEchoModel, який входить до Laravel Echo:
import { useEchoModel } from "@laravel/echo-react";
useEchoModel("App.Models.User", userId, ["UserUpdated"], (e) => {
console.log(e.model);
});
<script setup lang="ts">
import { useEchoModel } from "@laravel/echo-vue";
useEchoModel("App.Models.User", userId, ["UserUpdated"], (e) => {
console.log(e.model);
});
</script>
<script>
import { useEchoModel } from "@laravel/echo-svelte";
useEchoModel("App.Models.User", userId, ["UserUpdated"], (e) => {
console.log(e.model);
});
</script>
Ви також можете описати форму даних події моделі, отримавши кращу типобезпеку й зручність редагування:
type User = {
id: number;
name: string;
email: string;
};
useEchoModel<User, "App.Models.User">("App.Models.User", userId, ["UserUpdated"], (e) => {
console.log(e.model.id);
console.log(e.model.name);
});
Клієнтські події
Користуючись Pusher Channels, ви маєте увімкнути опцію «Client Events» у розділі «App Settings» вашої панелі застосунку, щоб надсилати клієнтські події.
Інколи вам може захотітися надіслати подію іншим підключеним клієнтам, узагалі не звертаючись до застосунку Laravel. Це особливо корисно для речей на кшталт сповіщень «набирає повідомлення», коли ви хочете попередити користувачів застосунку, що інший користувач набирає повідомлення на певному екрані.
Щоб надсилати клієнтські події, скористайтеся методом whisper з Echo:
Echo.private(`chat.${roomId}`)
.whisper('typing', {
name: this.user.name
});
import { useEcho } from "@laravel/echo-react";
const { channel } = useEcho(`chat.${roomId}`, ['update'], (e) => {
console.log('Chat event received:', e);
});
channel().whisper('typing', { name: user.name });
<script setup lang="ts">
import { useEcho } from "@laravel/echo-vue";
const { channel } = useEcho(`chat.${roomId}`, ['update'], (e) => {
console.log('Chat event received:', e);
});
channel().whisper('typing', { name: user.name });
</script>
<script>
import { useEcho } from "@laravel/echo-svelte";
const { channel } = useEcho(`chat.${roomId}`, ['update'], (e) => {
console.log('Chat event received:', e);
});
channel().whisper('typing', { name: user.name });
</script>
Щоб слухати клієнтські події, скористайтеся методом listenForWhisper:
Echo.private(`chat.${roomId}`)
.listenForWhisper('typing', (e) => {
console.log(e.name);
});
import { useEcho } from "@laravel/echo-react";
const { channel } = useEcho(`chat.${roomId}`, ['update'], (e) => {
console.log('Chat event received:', e);
});
channel().listenForWhisper('typing', (e) => {
console.log(e.name);
});
<script setup lang="ts">
import { useEcho } from "@laravel/echo-vue";
const { channel } = useEcho(`chat.${roomId}`, ['update'], (e) => {
console.log('Chat event received:', e);
});
channel().listenForWhisper('typing', (e) => {
console.log(e.name);
});
</script>
<script>
import { useEcho } from "@laravel/echo-svelte";
const { channel } = useEcho(`chat.${roomId}`, ['update'], (e) => {
console.log('Chat event received:', e);
});
channel().listenForWhisper('typing', (e) => {
console.log(e.name);
});
</script>
Сповіщення
Поєднавши бродкастинг подій зі сповіщеннями, ваш застосунок на JavaScript зможе отримувати нові сповіщення щойно вони з'являються, без оновлення сторінки. Перш ніж почати, обов'язково прочитайте документацію про канал сповіщень broadcast.
Щойно ви налаштували сповіщення на використання каналу broadcast, слухати події бродкастингу можна методом notification з Echo. Пам'ятайте: ім'я каналу має збігатися з назвою класу сутності, яка отримує сповіщення:
Echo.private(`App.Models.User.${userId}`)
.notification((notification) => {
console.log(notification.type);
});
import { useEchoModel } from "@laravel/echo-react";
const { channel } = useEchoModel('App.Models.User', userId);
channel().notification((notification) => {
console.log(notification.type);
});
<script setup lang="ts">
import { useEchoModel } from "@laravel/echo-vue";
const { channel } = useEchoModel('App.Models.User', userId);
channel().notification((notification) => {
console.log(notification.type);
});
</script>
<script>
import { useEchoModel } from "@laravel/echo-svelte";
const { channel } = useEchoModel('App.Models.User', userId);
channel().notification((notification) => {
console.log(notification.type);
});
</script>
У цьому прикладі всі сповіщення, надіслані екземплярам App\Models\User через канал broadcast, отримуватиме колбек. Колбек авторизації каналу App.Models.User.{id} уже є у файлі routes/channels.php вашого застосунку.
Припинення прослуховування сповіщень
Якщо ви хочете перестати слухати сповіщення, не виходячи з каналу, скористайтеся методом stopListeningForNotification:
const callback = (notification) => {
console.log(notification.type);
}
// Start listening...
Echo.private(`App.Models.User.${userId}`)
.notification(callback);
// Stop listening (callback must be the same)...
Echo.private(`App.Models.User.${userId}`)
.stopListeningForNotification(callback);