Документация Laravel 10.x
Здесь ты найдешь сниппеты по Laravel и полезные советы по веб-разработке.
Во многих современных веб-приложениях используются веб-сокеты для реализации мгновенных, обновляющихся в реальном времени пользовательских интерфейсов. Когда какие-то данные обновляются на сервере, обычно отправляется сообщение по соединению веб-сокета для обработки клиентом. Веб-сокеты предоставляют более эффективную альтернативу постоянному опросу сервера вашего приложения для отслеживания изменений данных, которые должны отображаться в вашем пользовательском интерфейсе.
Например, представьте, что ваше приложение может экспортировать данные пользователя в CSV-файл и отправить его по электронной почте. Однако создание этого CSV-файла занимает несколько минут, поэтому вы решаете создать и отправить CSV внутри очередной задачи. Когда CSV-файл создан и отправлен пользователю, мы можем использовать событийную трансляцию для отправки события App\Events\UserDataExported
, которое принимает наше JavaScript-приложение. Как только событие будет получено, мы можем отобразить сообщение пользователю, что его CSV отправлено ему, не заставляя его обновлять страницу.
Чтобы помочь вам создавать подобные функции, Laravel упрощает процесс "трансляции" ваших серверных событий Laravel events через соединение WebSocket. Трансляция ваших событий Laravel позволяет вам использовать одни и те же имена событий и данные между вашим серверным приложением Laravel и вашим клиентским JavaScript-приложением.
Основные концепции трансляции просты: клиенты подключаются к именованным каналам на фронтенде, в то время как ваше приложение Laravel транслирует события в эти каналы на бэкенде. Эти события могут содержать любые дополнительные данные, которые вы хотите сделать доступными на фронтенде.
По умолчанию Laravel включает два драйвера серверной трансляции на выбор: Pusher Channels и Ably. Тем не менее, пакеты, созданные сообществом, такие как laravel-websockets и soketi, предоставляют дополнительные драйверы трансляции, которые не требуют коммерческих поставщиков вещания.
Примечание Прежде чем приступить к трансляции событий, убедитесь, что вы прочли документацию Laravel по событиям и слушателям.
Для начала использования событийной трансляции Laravel нам нужно выполнить некоторую конфигурацию в приложении Laravel, а также установить несколько пакетов.
Трансляция событий выполняется драйвером серверной трансляции, который транслирует ваши события Laravel так, чтобы Laravel Echo (библиотека JavaScript) могла их получить в браузерном клиенте. Не волнуйтесь, мы рассмотрим каждую часть процесса установки пошагово.
Вся конфигурация трансляции событий вашего приложения хранится в конфигурационном файле config/broadcasting.php
. Laravel поддерживает несколько драйверов трансляции из коробки: Pusher Channels, Redis и драйвер log
для локальной разработки и отладки. Кроме того, включен драйвер null
, который позволяет полностью отключить трансляцию во время тестирования. В файле конфигурации config/broadcasting.php
приведен пример конфигурации для каждого из этих драйверов.
Прежде чем транслировать какие-либо события, вам сначала нужно зарегистрировать App\Providers\BroadcastServiceProvider
. В новых приложениях Laravel вам нужно только раскомментировать этот провайдер в массиве providers
файла конфигурации config/app.php
. Этот BroadcastServiceProvider
содержит код, необходимый для регистрации маршрутов и обратных вызовов авторизации трансляции.
Вам также нужно настроить и запустить очередной обработчик. Вся трансляция событий выполняется с использованием отложенных задач, чтобы время ответа вашего приложения серьезно не страдало от трансляции событий.
Если вы планируете транслировать ваши события с использованием Pusher Channels, вы должны установить SDK Pusher Channels PHP с помощью менеджера пакетов Composer:
composer require pusher/pusher-php-server
Затем вам следует настроить учетные данные Pusher Channels в файле конфигурации config/broadcasting.php
. Пример конфигурации Pusher Channels уже включен в этот файл, что позволяет быстро указать ключ, секрет и идентификатор приложения. Обычно эти значения должны быть установлены с помощью переменных окружения PUSHER_APP_KEY
, PUSHER_APP_SECRET
и PUSHER_APP_ID
переменных окружения:
PUSHER_APP_ID=your-pusher-app-idPUSHER_APP_KEY=your-pusher-keyPUSHER_APP_SECRET=your-pusher-secretPUSHER_APP_CLUSTER=mt1
Конфигурация pusher
файла config/broadcasting.php
также позволяет указать дополнительные options
, поддерживаемые Channels, такие как кластер.
Затем вам нужно изменить драйвер трансляции на pusher
в вашем файле .env
:
BROADCAST_DRIVER=pusher
Наконец, вы готовы установить и настроить Laravel Echo, который будет принимать транслируемые события на стороне клиента.
laravel-websockets и soketi предоставляют совместимые с Pusher серверы WebSocket для Laravel. Эти пакеты позволяют вам использовать все возможности трансляции Laravel без коммерческого поставщика WebSocket. Для получения дополнительной информации о установке и использовании этих пакетов обратитесь к нашей документации по альтернативам с открытым исходным кодом.
Примечание В документации ниже рассматривается использование Ably в режиме совместимости с Pusher. Однако команда Ably рекомендует и поддерживает драйвер и клиент Echo, способные использовать уникальные возможности, предлагаемые Ably. Для получения дополнительной информации о использовании поддерживаемых Ably драйверов обратитесь к документации по трансляции в Laravel от Ably.
Если вы планируете транслировать свои события с использованием Ably, вы должны установить SDK Ably PHP с использованием менеджера пакетов 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, который будет получать транслируемые события на стороне клиента.
Пакет laravel-websockets - это чистый PHP-пакет WebSocket, совместимый с Pusher, для Laravel. Этот пакет позволяет использовать все возможности трансляции Laravel без коммерческого поставщика WebSocket. Для получения дополнительной информации об установке и использовании этого пакета ознакомьтесь с официальной документацией.
Soketi - это сервер WebSocket на основе Node, совместимый с Pusher, для Laravel. Под капотом Soketi использует µWebSockets.js для обеспечения масштабируемости и скорости. Этот пакет позволяет использовать все возможности трансляции Laravel без коммерческого поставщика WebSocket. Для получения дополнительной информации об установке и использовании этого пакета ознакомьтесь с официальной документацией.
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 dev
Примечание Для получения дополнительной информации о компиляции JavaScript-активов вашего приложения ознакомьтесь с документацией по Vite.
Если у вас уже есть предварительно настроенный клиент Pusher Channels, который вы хотели бы использовать Echo, вы можете передать его в 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 в режиме совместимости с Pusher. Однако команда Ably рекомендует и поддерживает драйвер и клиент Echo, способные использовать уникальные возможности, предлагаемые Ably. Для получения дополнительной информации о использовании поддерживаемых Ably драйверов обратитесь к документации по трансляции в Laravel от Ably.
Laravel Echo - это библиотека JavaScript, которая упрощает подписку на каналы и прослушивание событий, транслируемых вашим драйвером трансляции с сервера. Вы можете установить Echo с помощью менеджера пакетов NPM. В этом примере мы также установим пакет pusher-js
.
Возможно, вы задаетесь вопросом, почему мы устанавливаем библиотеку pusher-js
, даже если мы используем Ably для трансляции наших событий. К счастью, Ably включает режим совместимости с Pusher, который позволяет нам использовать протокол Pusher при прослушивании событий в нашем клиентском приложении:
npm install --save-dev laravel-echo pusher-js
Прежде чем продолжить, вы должны включить поддержку протокола Pusher в настройках вашего приложения Ably. Вы можете включить эту функцию в разделе "Настройки адаптера протокола" на панели настроек вашего приложения Ably.
После установки Echo вы готовы создать новый экземпляр Echo в вашем JavaScript-приложении. Отличным местом для этого является конец файла resources/js/bootstrap.js
, который поставляется с фреймворком Laravel. По умолчанию в этом файле уже предоставлен пример конфигурации Echo; однако конфигурация по умолчанию в файле bootstrap.js
предназначена для Pusher. Вы можете скопировать приведенную ниже конфигурацию для перехода от конфигурации 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,});
Обратите внимание, что наша конфигурация Ably Echo ссылается на переменную окружения 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\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}
, чтобы указать, что часть "ID" имени канала является подстановочным символом.
Теперь все, что остается, - это прослушать событие в нашем JavaScript-приложении. Мы можем сделать это с использованием Laravel Echo. Сначала мы используем метод private
для подписки на частный канал. Затем мы можем использовать метод listen
для прослушивания события OrderShipmentStatusUpdated
. По умолчанию вещательное событие будет включать все общедоступные свойства события:
Echo.private(`orders.${orderId}`) .listen('OrderShipmentStatusUpdated', (e) => { console.log(e.order); });
Чтобы сообщить Laravel, что данное событие должно быть транслировано, вы должны реализовать интерфейс Illuminate\Contracts\Broadcasting\ShouldBroadcast
в классе события. Этот интерфейс уже импортирован во все классы событий, сгенерированные фреймворком, поэтому вы можете легко добавить его к любому из ваших событий.
Интерфейс ShouldBroadcast
требует реализации единственного метода: broadcastOn
. Метод broadcastOn
должен возвращать канал или массив каналов, на которых должно быть транслировано событие. Каналы должны быть экземплярами Channel
, PrivateChannel
или PresenceChannel
. Экземпляры Channel
представляют общедоступные каналы, на которые может подписаться любой пользователь, в то время как PrivateChannels
и PresenceChannels
представляют частные каналы, требующие авторизации каналов:
<?php namespace App\Events; use App\Models\User;use Illuminate\Broadcasting\Channel;use Illuminate\Broadcasting\InteractsWithSockets;use Illuminate\Broadcasting\PresenceChannel;use Illuminate\Broadcasting\PrivateChannel;use Illuminate\Contracts\Broadcasting\ShouldBroadcast;use Illuminate\Queue\SerializesModels; class ServerCreated implements ShouldBroadcast{ use SerializesModels; /** * Создать новый экземпляр события. */ public function __construct( public User $user, ) {} /** * Получить каналы, на которые должно транслироваться событие. * * @return array<int, \Illuminate\Broadcasting\Channel> */ public function broadcastOn(): array { return [ new PrivateChannel('user.'.$this->user->id), ]; }}
После реализации интерфейса ShouldBroadcast
вам нужно только запустить событие, как обычно. Как только событие будет запущено, очередная задача автоматически транслирует событие с использованием вашего указанного драйвера трансляции.
По умолчанию 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
автоматически помещает свои маршруты в группу промежуточного программного обеспечения web
; однако вы можете передать массив атрибутов маршрута методу, если хотите настроить назначенные атрибуты:
Broadcast::routes($attributes);
По умолчанию Echo будет использовать конечную точку /broadcasting/auth
для авторизации доступа к каналу. Однако вы можете указать свою собственную конечную точку авторизации, передав конфигурационную опцию authEndpoint
в ваш экземпляр Echo:
window.Echo = new Echo({ broadcaster: 'pusher', // ... authEndpoint: '/custom/endpoint/auth'});
Вы можете настроить способ выполнения 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-маршруты, маршруты каналов также могут использовать неявное и явное привязку моделей к маршруту. Например, вместо получения строки или числового идентификатора заказа, вы можете запросить фактический экземпляр модели 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{ /** * Создать новый экземпляр канала. */ public function __construct() { // ... } /** * Аутентифицировать доступ пользователя к каналу. */ 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
для указания вещателю не транслировать событие текущему пользователю.
Внимание Вашему событию необходимо использовать трейт
Illuminate\Broadcasting\InteractsWithSockets
, чтобы вызывать методtoOthers
.
При инициализации экземпляра Laravel Echo к соединению присваивается идентификатор сокета. Если вы используете глобальный Axios для выполнения HTTP-запросов из вашего JavaScript-приложения, идентификатор сокета автоматически добавляется ко всем исходящим запросам в виде заголовка X-Socket-ID
. Затем, при вызове метода toOthers
, Laravel извлечет идентификатор сокета из заголовка и укажет вещателю не транслировать событие текущему пользователю.
Если вы не используете глобальный экземпляр Axios, вам нужно будет вручную настроить ваше JavaScript-приложение для отправки заголовка X-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}`);
Вы можете заметить, что в приведенных выше примерах мы не указывали полное пространство имен App\Events
для классов событий. Это потому, что Echo автоматически предполагает, что события находятся в пространстве имен App\Events
. Однако вы можете настроить корневое пространство имен, передавая параметр конфигурации namespace
при создании Echo:
window.Echo = new Echo({ broadcaster: 'pusher', // ... namespace: 'App.Other.Namespace'});
В качестве альтернативы вы можете добавить префикс к классам событий символом .
при их подписке с помощью Echo. Это позволит вам всегда указывать полностью квалифицированное имя класса:
Echo.channel('orders') .listen('.Namespace\\Event\\Class', (e) => { // ... });
Каналы 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, вы можете использовать метод 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 могут получать события, так же как и общедоступные или приватные каналы. Используя пример чат-комнаты, мы можем хотеть транслировать события 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. Если экземпляр модели Eloquent возвращается методом broadcastOn
вашей модели (или содержится в массиве, возвращаемом методом), 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 будет использовать соглашения о канале для модели, обсуждаемые выше, чтобы преобразовать модель Eloquent в строку имени канала:
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 framework.