Skip to content

ブロードキャスト

はじめに

多くの現代の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

Note

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

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

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

イベントブロードキャストは、サーバーサイドのブロードキャストドライバによって実現され、Laravelイベントをブロードキャストして、ブラウザクライアント内で受信できるようにします。心配しないでください。インストールプロセスの各部分を段階的に説明します。

設定

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

Laravelはいくつかのブロードキャストドライバをデフォルトでサポートしています:Laravel ReverbPusher ChannelsAbly、およびローカル開発とデバッグ用の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をインストールすることもできます。

composer require laravel/reverb

パッケージがインストールされたら、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

Note

以下のドキュメントでは、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ライブラリです。NPMパッケージマネージャを介してEchoをインストールできます。この例では、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

Warning

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

Pusher Channels

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

install:broadcasting Artisanコマンドは自動的にlaravel-echopusher-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

Note

アプリケーションの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

Note

以下のドキュメントでは、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

Note

アプリケーションのJavaScriptアセットのコンパイルについて詳しく学ぶには、Viteのドキュメントを参照してください。

概念の概要

Laravelのイベントブロードキャストにより、サーバーサイドのLaravelイベントをWebSocketを使用してクライアントサイドのJavaScriptアプリケーションにブロードキャストすることができます。現在、LaravelにはPusher ChannelsAblyのドライバが付属しています。イベントは、Laravel Echo JavaScriptパッケージを使用してクライアントサイドで簡単に消費できます。

イベントは「チャンネル」を介してブロードキャストされ、チャンネルは公開または非公開として指定できます。アプリケーションの訪問者は、認証や承認なしに公開チャンネルを購読できます。ただし、非公開チャンネルを購読するには、ユーザーは認証され、そのチャンネルをリッスンする権限が必要です。

サンプルアプリケーションの使用

イベントブロードキャストの各コンポーネントに飛び込む前に、eコマースストアを例にして高レベルの概要を説明しましょう。

アプリケーションで、ユーザーが注文の配送状況を表示できるページがあるとします。また、配送状況の更新がアプリケーションによって処理されるときにOrderShipmentStatusUpdatedイベントが発生するとします:

use App\Events\OrderShipmentStatusUpdated;

OrderShipmentStatusUpdated::dispatch($order);

ShouldBroadcastインターフェース

ユーザーが注文の一つを表示しているとき、状況の更新を表示するためにページを更新する必要はありません。代わりに、更新が作成されたときにアプリケーションにブロードキャストしたいと考えています。そのため、OrderShipmentStatusUpdatedイベントにShouldBroadcastインターフェースをマークする必要があります。これにより、Laravelにイベントが発生したときにブロードキャストするよう指示します:

<?php

namespace App\Events;

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

class OrderShipmentStatusUpdated implements ShouldBroadcast
{
    /**
     * 注文インスタンス。
     *
     * @var \App\Models\Order
     */
    public $order;
}

ShouldBroadcastインターフェースは、イベントにbroadcastOnメソッドを定義する必要があります。このメソッドは、イベントがブロードキャストされるチャンネルを返す役割を果たします。生成されたイベントクラスには、このメソッドの空のスタブが既に定義されているため、詳細を埋めるだけです。注文の作成者だけが状況の更新を見ることができるように、注文に関連付けられた非公開チャンネルでイベントをブロードキャストします:

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

/**
 * イベントがブロードキャストされるチャンネルを取得します。
 */
public function broadcastOn(): Channel
{
    return new PrivateChannel('orders.'.$this->order->id);
}

イベントを複数のチャンネルでブロードキャストしたい場合は、代わりにarrayを返すことができます:

use Illuminate\Broadcasting\PrivateChannel;

/**
 * イベントがブロードキャストされるチャンネルを取得します。
 *
 * @return array<int, \Illuminate\Broadcasting\Channel>
 */
public function broadcastOn(): array
{
    return [
        new PrivateChannel('orders.'.$this->order->id),
        // ...
    ];
}

チャンネルの認可

ユーザーが非公開チャンネルを購読できるようにするには、チャンネルの認可ルールを定義する必要があります。これは、routes/channels.phpファイルで行います。この例では、orders.1チャンネルを購読しようとするユーザーが実際にその注文の所有者であることを確認する必要があります:

use App\Models\Order;

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

channelメソッドは2つの引数を取ります:チャンネルの名前と、ユーザーがチャンネルを購読できるかどうかを決定するtrueまたはfalseを返すクロージャです。

認可クロージャは、現在認証されているユーザーと、チャンネル名に含まれるすべてのワイルドカードパラメータを受け取ります。この例では、{orderId}プレースホルダーを使用して、チャンネル名の「order 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 メソッドは、イベントをブロードキャストするチャンネルまたはチャンネルの配列を返す必要があります。チャンネルは ChannelPrivateChannel、または PresenceChannel のインスタンスである必要があります。Channel のインスタンスは誰でも購読できるパブリックチャンネルを表し、PrivateChannelsPresenceChannelsチャンネルの承認 が必要なプライベートチャンネルを表します。

<?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アプリケーションからそのパブリックデータにアクセスできます。したがって、例えばイベントにEloquentモデルを含む単一の $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;
}

Note

これらの問題を回避する方法について詳しくは、キュージョブとデータベーストランザクション に関するドキュメントを参照してください。

チャンネルの承認

プライベートチャンネルは、現在認証されているユーザーが実際にそのチャンネルをリッスンできるかどうかを承認する必要があります。これは、チャンネル名を含む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 Artisanコマンドを使用して表示できます:

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

Warning

HTTPルートモデルバインディングとは異なり、チャンネルモデルバインディングは自動的な暗黙的モデルバインディングスコープをサポートしていません。ただし、これはほとんどのチャンネルが単一モデルのユニークなプライマリキーに基づいてスコープされるため、問題になることはほとんどありません。

認証コールバック認証

プライベートおよびプレゼンスブロードキャストチャンネルは、アプリケーションのデフォルトの認証ガードを介して現在のユーザーを認証します。ユーザーが認証されていない場合、チャンネル認証は自動的に拒否され、認証コールバックは実行されません。ただし、必要に応じて、受信リクエストを認証するために複数のカスタムガードを割り当てることができます:

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

チャンネルクラスの定義

アプリケーションが多くの異なるチャンネルを消費している場合、routes/channels.phpファイルは肥大化する可能性があります。そのため、チャンネルを認証するためにクロージャを使用する代わりに、チャンネルクラスを使用できます。チャンネルクラスを生成するには、make:channel Artisanコマンドを使用します。このコマンドは新しいチャンネルクラスをApp/Broadcastingディレクトリに配置します。

php artisan make:channel OrderChannel

次に、チャンネルをroutes/channels.phpファイルに登録します:

use App\Broadcasting\OrderChannel;

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

最後に、チャンネルクラスのjoinメソッドにチャンネルの認証ロジックを配置できます。この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;
    }
}

Note

Laravelの他の多くのクラスと同様に、チャンネルクラスはサービスコンテナによって自動的に解決されます。したがって、チャンネルのコンストラクタで必要な依存関係をタイプヒントで指定できます。

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

イベントを定義し、ShouldBroadcastインターフェースでマークしたら、イベントのディスパッチメソッドを使用してイベントを発火するだけです。イベントディスパッチャは、イベントがShouldBroadcastインターフェースでマークされていることを認識し、イベントをブロードキャストのためにキューに入れます:

use App\Events\OrderShipmentStatusUpdated;

OrderShipmentStatusUpdated::dispatch($order);

他のユーザーのみにブロードキャスト

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

use App\Events\OrderShipmentStatusUpdated;

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

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

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

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

Warning

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

設定

Laravel Echoインスタンスを初期化すると、ソケットIDが接続に割り当てられます。グローバルなAxiosインスタンスを使用してJavaScriptアプリケーションからHTTPリクエストを行う場合、ソケット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 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) => {
        // ...
    });

モデルのブロードキャスト

Warning

モデルのブロードキャストに関する以下のドキュメントを読む前に、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の場合、Illuminate\Broadcasting\PrivateChannelインスタンスに変換され、名前はApp.Models.User.1になります。もちろん、モデルのbroadcastOnメソッドからEloquentモデルインスタンスを返すだけでなく、完全な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モデルでid1の場合、文字列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という名前のイベントをブロードキャストします。

必要に応じて、モデルにbroadcastAsbroadcastWithメソッドを追加することで、カスタムのブロードキャスト名とペイロードを定義できます。これらのメソッドは、発生しているモデルイベント/操作の名前を受け取り、各モデル操作に対してイベントの名前とペイロードをカスタマイズできます。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);
    });

クライアントイベント

Note

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

場合によっては、Laravelアプリケーションにアクセスせずに、他の接続されたクライアントにイベントをブロードキャストしたいことがあります。これは、例えば「入力中」通知のようなもので、特定の画面で他のユーザーがメッセージを入力していることをアプリケーションのユーザーに警告したい場合に特に便利です。

クライアントイベントをブロードキャストするには、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ファイルに含まれています。

ユーザーノート