メインコンテンツまでスキップ

ブロードキャスト

はじめに

多くの現代のWebアプリケーションでは、WebSocketsが使用されてリアルタイムで更新されるユーザーインターフェースを実装します。サーバー上でデータが更新されると、通常はWebSocket接続を介してクライアントが処理するためのメッセージが送信されます。WebSocketsは、UIに反映されるべきデータの変更をアプリケーションのサーバーを継続的にポーリングするよりも効率的な代替手段を提供します。

たとえば、あなたのアプリケーションがユーザーのデータをCSVファイルにエクスポートしてそれをメールで送信できるようになっているとします。ただし、このCSVファイルを作成するのに数分かかるため、キューイングされたジョブ内でCSVを作成してメールすることを選択します。CSVが作成されてユーザーにメールされたら、イベントブロードキャストを使用して App\Events\UserDataExported イベントをディスパッチし、アプリケーションのJavaScriptで受信します。イベントを受信したら、ユーザーにCSVがメールで送信されたことを通知するメッセージを表示できます。ページを更新する必要はありません。

このような機能を構築するのを支援するために、LaravelはサーバーサイドのLaravel イベントをWebSocket接続経由で「ブロードキャスト」することを容易にします。Laravelイベントをブロードキャストすることで、サーバーサイドのLaravelアプリケーションとクライアントサイドのJavaScriptアプリケーションの間で同じイベント名とデータを共有できます。

ブロードキャストの背後にある基本的なコンセプトはシンプルです。クライアントはフロントエンドで名前付きチャンネルに接続し、Laravelアプリケーションはこれらのチャンネルにイベントをブロードキャストします。これらのイベントには、フロントエンドで利用可能にしたい追加のデータを含めることができます。

サポートされているドライバー

デフォルトでは、Laravelには選択できるサーバーサイドブロードキャストドライバーが3つ含まれています: Laravel ReverbPusher Channels、および Ably

注記

イベントブロードキャストに取り組む前に、Laravelのイベントとリスナーに関するドキュメントを読んでいることを確認してください。

サーバーサイドのインストール

Laravelのイベントブロードキャストを使用する準備をするには、Laravelアプリケーション内でのいくつかの設定といくつかのパッケージのインストールが必要です。

イベントブロードキャストは、サーバーサイドのブロードキャストドライバーによって達成され、Laravelイベントをブロードキャストして、ブラウザクライアント内でLaravel Echo(JavaScriptライブラリ)がそれらを受信できるようにします。心配しないでください - インストールプロセスの各部分をステップバイステップで説明します。

設定

アプリケーションのイベントブロードキャストのすべての設定は、config/broadcasting.php 構成ファイルに保存されます。このディレクトリがアプリケーションに存在しない場合は心配しないでください。install:broadcasting Artisan コマンドを実行すると作成されます。

Laravel は、いくつかのブロードキャストドライバをデフォルトでサポートしています: Laravel Reverb, Pusher Channels, Ably、そしてローカル開発とデバッグ用の log ドライバが含まれています。さらに、テスト中にブロードキャストを無効にすることができる null ドライバも含まれています。各ドライバの構成例が config/broadcasting.php 構成ファイルに含まれています。

インストール

デフォルトでは、新しい Laravel アプリケーションではブロードキャストが有効になっていません。install:broadcasting Artisan コマンドを使用してブロードキャストを有効にできます:

php artisan install:broadcasting

install:broadcasting コマンドは config/broadcasting.php 構成ファイルを作成します。さらに、アプリケーションのブロードキャスト認証ルートとコールバックを登録できる routes/channels.php ファイルも作成されます。

キューの設定

イベントをブロードキャストする前に、まず キューワーカー を設定して実行する必要があります。すべてのイベントブロードキャストはキューにジョブとして処理されるため、アプリケーションの応答時間がイベントのブロードキャストによって深刻に影響を受けないようになっています。

Reverb

install:broadcasting コマンドを実行すると、Laravel Reverb のインストールを促されます。もちろん、Composer パッケージマネージャを使用して Reverb を手動でインストールすることもできます。Reverb は現在ベータ版なので、明示的にベータリリースをインストールする必要があります:

composer require laravel/reverb:@beta

パッケージがインストールされたら、Reverb のインストールコマンドを実行して構成を公開し、Reverb の必要な環境変数を追加し、アプリケーションでイベントブロードキャストを有効にできます。

php artisan reverb:install

詳しいReverbのインストールおよび使用方法については、Reverbのドキュメントを参照してください。

Pusher Channels

イベントをPusher Channelsを使用してブロードキャストする予定がある場合は、Composerパッケージマネージャを使用してPusher Channels PHP SDKをインストールする必要があります:

composer require pusher/pusher-php-server

次に、config/broadcasting.php構成ファイルでPusher Channelsの認証情報を設定する必要があります。このファイルには、キー、シークレット、およびアプリケーションIDを迅速に指定できるように、例としてPusher Channelsの構成が既に含まれています。通常、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"

config/broadcasting.phpファイルのpusher構成では、Channelsでサポートされている追加のoptionsを指定することもできます。たとえば、クラスタを指定することができます。

その後、アプリケーションの.envファイルでBROADCAST_CONNECTION環境変数をpusherに設定してください:

BROADCAST_CONNECTION=pusher

最後に、クライアントサイドでブロードキャストイベントを受信するLaravel Echoのインストールと構成を行う準備が整います。

Ably

注記

以下のドキュメントでは、Ablyを「Pusher互換」モードで使用する方法について説明しています。ただし、Ablyチームは、Ablyが提供する独自の機能を活用できるブロードキャスターおよびEchoクライアントを推奨およびメンテナンスしています。Ablyがメンテナンスするドライバーの使用方法については、AblyのLaravelブロードキャスタードキュメントを参照してください。

イベントをAblyを使用してブロードキャストする予定がある場合は、Composerパッケージマネージャを使用してAbly PHP SDKをインストールする必要があります:

composer require ably/ably-php

次に、config/broadcasting.php構成ファイルでAblyの認証情報を設定する必要があります。このファイルには、キーを迅速に指定できるように、例としてAblyの構成が既に含まれています。通常、この値はABLY_KEY 環境変数を介して設定する必要があります:

ABLY_KEY=your-ably-key

次に、アプリケーションの .env ファイルで BROADCAST_CONNECTION 環境変数を ably に設定してください:

BROADCAST_CONNECTION=ably

最後に、Laravel Echo をインストールして設定する準備が整いました。これにより、クライアント側でブロードキャストイベントを受信することができます。

クライアントサイドのインストール

Reverb

Laravel Echo は、サーバーサイドのブロードキャストドライバーによってブロードキャストされたイベントに購読し、リッスンすることを簡単にするJavaScriptライブラリです。Echo は NPM パッケージマネージャを介してインストールすることができます。この例では、Reverb は WebSocket のサブスクリプション、チャンネル、およびメッセージに Pusher プロトコルを利用しているため、pusher-js パッケージもインストールします:

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

Echo をインストールしたら、アプリケーションの JavaScript で新しい Echo インスタンスを作成する準備が整いました。これを行うのに最適な場所は、Laravel フレームワークに含まれている resources/js/bootstrap.js ファイルの末尾です。デフォルトでは、このファイルには既に例として Echo の設定が含まれています - 単にそれをコメント解除して、broadcaster 設定オプションを reverb に更新するだけです:

import Echo from 'laravel-echo';

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

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

次に、アプリケーションのアセットをコンパイルする必要があります:

npm run build
警告

Laravel Echo の reverb ブロードキャスターには laravel-echo v1.16.0 以降が必要です。

Pusher Channels

Laravel Echo は、サーバーサイドのブロードキャストドライバーによってブロードキャストされたイベントに購読し、リッスンすることを簡単にするJavaScriptライブラリです。Echo はまた、WebSocket のサブスクリプション、チャンネル、およびメッセージの実装に pusher-js NPM パッケージを活用しています。

install:broadcasting Artisan コマンドは、laravel-echo および pusher-js パッケージを自動的にインストールしますが、NPM を介してこれらのパッケージを手動でインストールすることもできます:

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

Echoをインストールしたら、アプリケーションのJavaScriptで新しいEchoインスタンスを作成する準備が整います。install:broadcastingコマンドは、resources/js/echo.jsにEchoの設定ファイルを作成しますが、このファイルのデフォルト設定はLaravel Reverb向けに意図されています。以下の設定をコピーして、Pusherに設定を移行してください:

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

次に、アプリケーションの.envファイルにPusherの環境変数の適切な値を定義する必要があります。これらの変数がすでに.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構成オプションを介してEchoに渡すことができます:

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

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

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

Ably

注記

以下のドキュメントでは、Ablyを「Pusher互換」モードで使用する方法について説明しています。ただし、Ablyチームは、Ablyが提供する固有の機能を活用できるブロードキャスターとEchoクライアントを推奨し、メンテナンスしています。Ablyがメンテナンスしているドライバーを使用する詳細については、AblyのLaravelブロードキャスタードキュメントを参照してください。

Laravel Echoは、サーバーサイドのブロードキャスティングドライバーによってブロードキャストされるイベントを購読し、リッスンすることを簡単にするJavaScriptライブラリです。Echoはまた、WebSocketのサブスクリプション、チャンネル、メッセージのためにPusherプロトコルを実装するためにpusher-js NPMパッケージを活用しています。

install:broadcasting Artisanコマンドは、laravel-echopusher-jsパッケージを自動的にインストールしますが、NPMを使用してこれらのパッケージを手動でインストールすることもできます:

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

続行する前に、Ablyアプリケーションの設定でPusherプロトコルサポートを有効にする必要があります。これを行うには、Ablyアプリケーションの設定ダッシュボードの「Protocol Adapter Settings」セクションでこの機能を有効にできます。

Echoがインストールされたら、アプリケーションのJavaScriptで新しいEchoインスタンスを作成する準備が整います。install:broadcastingコマンドは、resources/js/echo.jsにEchoの設定ファイルを作成しますが、このファイルのデフォルト設定はLaravel Reverb向けです。以下の設定をコピーして、設定を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イベントをドライバーベースのWebSocketアプローチを使用してクライアントサイドのJavaScriptアプリケーションにブロードキャストできます。現在、LaravelにはPusher ChannelsAblyのドライバーが付属しています。これらのイベントは、Laravel Echo JavaScriptパッケージを使用してクライアントサイドで簡単に消費できます。

イベントは「チャンネル」を介してブロードキャストされ、これらは公開または非公開として指定できます。アプリケーションの訪問者は、認証や承認なしで公開チャンネルにサブスクライブできますが、非公開チャンネルにサブスクライブするには、ユーザーがそのチャンネルでリッスンするために認証および承認されている必要があります。

使用例アプリケーション

イベントブロードキャストの各コンポーネントに入る前に、例として電子商取引ストアを使用した高レベルの概要を見てみましょう。

当社のアプリケーションでは、ユーザーが注文の配送状況を表示するページがあると仮定しましょう。また、アプリケーションが配送状況の更新を処理するときに OrderShipmentStatusUpdated イベントが発生すると仮定しましょう:

use App\Events\OrderShipmentStatusUpdated;

OrderShipmentStatusUpdated::dispatch($order);

ShouldBroadcast インターフェース

ユーザーが自分の注文の1つを表示しているとき、ページを更新して状態の更新を表示する必要はありません。代わりに、作成されるときにアプリケーションに更新をブロードキャストしたいと考えています。そのため、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 インターフェースでは、イベントがブロードキャストするチャンネルを定義する必要があります。このメソッドは、イベントがブロードキャストするチャンネルを返す責任があります。このメソッドの空のスタブは、生成されたイベントクラスにすでに定義されているため、詳細を記入する必要があります。注文の作成者だけが状態の更新を表示できるようにしたいので、注文に関連付けられたプライベートチャンネルでイベントをブロードキャストします:

    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 を返すコールバックの2つの引数を受け入れます。

すべての認証コールバックは、現在認証されているユーザーを最初の引数として、追加のワイルドカードパラメータをその後の引数として受け取ります。この例では、チャンネル名の "ID" 部分がワイルドカードであることを示す {orderId} プレースホルダを使用しています。

イベントブロードキャストのリスニング

次に、JavaScript アプリケーションでイベントをリッスンするだけです。これは Laravel Echo を使用して行います。まず、private メソッドを使用してプライベートチャンネルにサブスクライブします。その後、listen メソッドを使用して OrderShipmentStatusUpdated イベントをリッスンできます。デフォルトでは、イベントのすべての公開プロパティがブロードキャストイベントに含まれます:

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

ブロードキャストイベントの定義

特定のイベントをブロードキャストする必要があることを Laravel に通知するには、イベントクラスで Illuminate\Contracts\Broadcasting\ShouldBroadcast インターフェースを実装する必要があります。このインターフェースは、フレームワークによって生成されたすべてのイベントクラスに既にインポートされているため、簡単にイベントに追加できます。

ShouldBroadcast インターフェースでは、broadcastOn メソッドを実装する必要があります。broadcastOn メソッドは、イベントがブロードキャストされるべきチャンネルまたはチャンネルの配列を返す必要があります。チャンネルは、ChannelPrivateChannel、または 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 プロパティが含まれる場合、そのイベントのブロードキャスト ペイロードは次のようになります:

{
"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 プロパティを定義することができます:

    /**
* The name of the queue connection to use when broadcasting the event.
*
* @var string
*/
public $connection = 'redis';

/**
* The name of the queue on which to place the broadcasting job.
*
* @var string
*/
public $queue = 'default';

また、イベントで broadcastQueue メソッドを定義することで、キュー名をカスタマイズすることもできます:

    /**
* The name of the queue on which to place the broadcasting job.
*/
public function broadcastQueue(): string
{
return 'default';
}

デフォルトのキュードライバーの代わりに sync キューを使用してイベントをブロードキャストしたい場合は、ShouldBroadcast インターフェースの代わりに ShouldBroadcastNow インターフェースを実装することができます:

    <?php

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;
}
注記

これらの問題を回避する方法について詳しく知るには、queued jobs and database transactions のドキュメントを参照してください。

チャンネルの認可

プライベートチャンネルを使用する場合、現在認証されているユーザーが実際にそのチャンネルを聞くことができるかどうかを認可する必要があります。これは、チャンネル名を含むHTTPリクエストをLaravelアプリケーションに送信し、アプリケーションがそのチャンネルを聞くことができるかどうかを決定することで達成されます。Laravel Echo を使用する場合、プライベートチャンネルのサブスクリプションを認可するためのHTTPリクエストは自動的に行われます。

ブロードキャストが有効になっている場合、Laravelは自動的に /broadcasting/auth ルートを登録して認可リクエストを処理します。/broadcasting/auth ルートは自動的に web ミドルウェアグループ内に配置されます。

認可コールバックの定義

次に、現在認証されているユーザーが特定のチャンネルを聞くことができるかどうかを実際に決定するロジックを定義する必要があります。これは、install:broadcasting Artisanコマンドによって作成された 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を返すコールバックの2つの引数を受け入れます。

すべての認証コールバックは、最初の引数として現在認証されているユーザー、およびその後の引数として追加のワイルドカードパラメータを受け取ります。この例では、チャンネル名の「ID」部分がワイルドカードであることを示す{orderId}プレースホルダを使用しています。

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ファイルは肥大化する可能性があります。そのため、チャンネルを承認するためにクロージャを使用する代わりに、チャンネルクラスを使用することができます。チャンネルクラスを生成するには、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 インターフェースでマークした後は、イベントの dispatch メソッドを使用するだけで良いです。イベントディスパッチャは、イベントが ShouldBroadcast インターフェースでマークされていることに気づき、イベントをブロードキャスト用にキューに入れます:

    use App\Events\OrderShipmentStatusUpdated;

OrderShipmentStatusUpdated::dispatch($order);

他のユーザーにのみ

イベントブロードキャストを利用するアプリケーションを構築する際には、現在のユーザーを除く特定のチャンネルのすべての購読者にイベントをブロードキャストする必要がある場合があります。これは broadcast ヘルパーと toOthers メソッドを使用して実現できます:

    use App\Events\OrderShipmentStatusUpdated;

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

toOthers メソッドを使用するタイミングをより理解するために、タスクリストアプリケーションを想像してみましょう。ユーザーはタスク名を入力して新しいタスクを作成できるアプリケーションを考えてみましょう。タスクを作成するために、アプリケーションは /task URL にリクエストを行い、タスクの作成をブロードキャストし、新しいタスクのJSON表現を返します。JavaScriptアプリケーションがエンドポイントからの応答を受け取ると、新しいタスクを直接タスクリストに挿入するかもしれません:

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

ただし、タスクの作成もブロードキャストされます。JavaScriptアプリケーションがこのイベントをリッスンしてタスクリストにタスクを追加する場合、リストには重複したタスクが表示されます:エンドポイントからのものとブロードキャストからのものがあります。この問題は、toOthers メソッドを使用してブロードキャストを現在のユーザーに送信しないように指示することで解決できます。

警告

イベントは、toOthers メソッドを呼び出すために Illuminate\Broadcasting\InteractsWithSockets トレイトを使用する必要があります。

設定

Laravel Echo インスタンスを初期化すると、接続にソケット ID が割り当てられます。JavaScript アプリケーションから HTTP リクエストを行うためにグローバルな Axios インスタンスを使用している場合、ソケット ID は X-Socket-ID ヘッダーとしてすべての送信リクエストに自動的に添付されます。その後、toOthers メソッドを呼び出すと、Laravel はヘッダーからソケット ID を抽出し、そのソケット ID を持つ接続にブロードキャストしないようにブロードキャスターに指示します。

グローバルな Axios インスタンスを使用していない場合は、JavaScript アプリケーションを手動で構成して、すべての送信リクエストに X-Socket-ID ヘッダーを送信する必要があります。Echo.socketId メソッドを使用してソケット ID を取得できます:

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 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')

チャンネルを離れる

チャンネルを離れるには、Echo インスタンスで leaveChannel メソッドを呼び出すことができます:

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

チャンネルとそれに関連するプライベートおよびプレゼンスチャンネルを離れたい場合は、leave メソッドを呼び出すことができます:

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

名前空間

上記の例で気づいたかもしれませんが、イベントクラスの完全な App\Events ネームスペースを指定していません。これは、Echo が自動的にイベントが App\Events ネームスペースにあると仮定するためです。ただし、Echo をインスタンス化する際に namespace 構成オプションを渡すことでルートネームスペースを設定することができます:

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

または、Echo を使用してこれらにサブスクライブする際にイベントクラスに . を付けることができます。これにより、常に完全修飾クラス名を指定できます:

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

プレゼンスチャンネル

プレゼンスチャンネルは、プライベートチャンネルのセキュリティを活用しながら、チャンネルに登録しているユーザーを認識する追加機能を公開します。これにより、他のユーザーが同じページを表示しているときにユーザーに通知する、またはチャットルームの参加者をリストアップするなど、強力で協力的なアプリケーション機能を簡単に構築できます。

プレゼンスチャンネルの認可

すべてのプレゼンスチャンネルはプライベートチャンネルでもあります。したがって、ユーザーはそれらにアクセスするために認可を受ける必要があります。ただし、プレゼンスチャンネルの認可コールバックを定義する際には、ユーザーがチャンネルに参加することが許可されている場合に true を返すのではなく、ユーザーに関するデータの配列を返す必要があります。

認可コールバックによって返されるデータは、JavaScript アプリケーション内のプレゼンスチャンネルイベントリスナーで使用できます。ユーザーがプレゼンスチャンネルに参加することが許可されていない場合は、false または null を返す必要があります:

    use App\Models\User;

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

プレゼンスチャンネルへの参加

プレゼンスチャンネルに参加するには、Echo の join メソッドを使用できます。join メソッドは PresenceChannel 実装を返し、listen メソッドを公開するだけでなく、herejoiningleaving イベントにサブスクライブすることができます。

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 メソッドは、認証エンドポイントが 200 以外の HTTP ステータスコードを返す場合や、返された JSON を解析する際に問題がある場合に実行されます。

プレゼンスチャネルへのブロードキャスト

プレゼンスチャネルは、パブリックチャネルやプライベートチャネルと同様にイベントを受信することができます。チャットルームの例を使用して、ルームのプレゼンスチャネルに NewMessage イベントをブロードキャストしたい場合、イベントの broadcastOn メソッドから PresenceChannel のインスタンスを返します:

    /**
* 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();

他の種類のイベントと同様に、Echo の listen メソッドを使用してプレゼンスチャネルに送信されたイベントをリッスンすることができます:

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 引数を受け取ることに気づいたかもしれません。この引数には、モデルで発生したイベントの種類が含まれ、createdupdateddeletedtrashed、または 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 モデルの id1 の場合、App.Models.User.1 という名前の Illuminate\Broadcasting\PrivateChannel インスタンスに変換されます。もちろん、モデルの broadcastOn メソッドから Eloquent モデルインスタンスを返すだけでなく、モデルのチャンネル名を完全に制御するために完全な 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 メソッドを呼び出すことができます。たとえば、このメソッドは、id1App\Models\User モデルに対して 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('.PostUpdated', (e) => {
console.log(e.model);
});

クライアントイベント

注記

Pusher Channels を使用する場合、クライアントイベントを送信するためには、アプリケーションダッシュボード の "App Settings" セクションで "Client Events" オプションを有効にする必要があります。

時には、Laravel アプリケーションにアクセスせずに他の接続されたクライアントにイベントをブロードキャストしたい場合があります。これは、"typing" 通知などの場合に特に便利です。このような場合、アプリケーションのユーザーに、別のユーザーが特定の画面でメッセージを入力していることを通知したいときに使用できます。

クライアントイベントをブロードキャストするには、Echo の whisper メソッドを使用できます:

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

クライアントイベントをリッスンするには、listenForWhisper メソッドを使用できます:

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

通知

イベントブロードキャストと 通知 を組み合わせることで、JavaScript アプリケーションはページをリフレッシュすることなく新しい通知を受信できます。始める前に、ブロードキャスト通知チャンネルの使用に関するドキュメント をよく読んでください。

通知をブロードキャストチャンネルを使用するように構成した後、Echo の notification メソッドを使用してブロードキャストイベントをリッスンできます。チャンネル名は、通知を受け取るエンティティのクラス名と一致する必要があります:

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

この例では、broadcast チャンネルを介して App\Models\User インスタンスに送信されるすべての通知が、コールバックによって受信されます。App.Models.User.{id} チャンネルのチャンネル認証コールバックは、アプリケーションの routes/channels.php ファイルに含まれています。