こんにちは!
今回は「LaravelでPusherとBroadcastという技術を使ってリアルタイム通信を行う」というテーマで書いていきます。
「Laravelでのリアルタイムな通信方法に興味がある」
「LaravelのBroadcastについて、具体的な実装方法が知りたい」
「LaravelでPusherを使ってみたい」
本記事は、このようなニーズに応える記事になります。
LaravelのBroadcastという技術を使うことで、サーバー側とクライアント側でのデータのやり取りをリアルタイムに通信することができるようになります。この技術は、主にリアルタイム性の求められるチャットサービスや通知などの機能で活躍することが多いです。また、本記事では外部サービスであるPusherを利用してリアルタイム通信を実現します。
本記事では、PusherやBroadcastの基本的な使い方をサンプルコード付きで説明していきます。
✔️ 筆者の経験
・プログラミング歴3年の現役Webエンジニア
・複数の自社サービスの立ち上げを経験
Broadcast概要
ブロードキャストはイメージとしてはテレビのようなものです。
チャンネルを作成して、チャンネルを介してイベントを放送することで、サーバー側とクライアント側でリアルタイムでの通信を可能とする技術です。実際には、WebSocket接続を介してサーバー側のLaravelイベントをブロードキャスト(放送)しており、JavaScriptはそのイベントを受信して表示します。
リアルタイムでの通信というのは、ページ更新をする必要がなく、サーバー・クライアント間でデータのやり取りを行うことができるということです。
大まかに、実装方法としては以下のような流れになります。
- Laravelでイベントクラスを作成
- チャンネルの認証設定
- チャンネルの認可設定
- イベント発行
- JavaScriptでイベントをリッスン
基本的な実装手順
それでは、次に具体的な実装方法について見ていきましょう。
下準備
まずは、必要なパッケージやモジュールなどをインストールする必要があります。Laravel側ではPusherチャンネル、JavaScript側ではLaravel Echoが必要となります。もちろん、選択肢はこれだけではなく他にもありますが、今回はデフォルトでサポートされているこの2つを使用します。
Pusherアカウントをお持ちでない方は、先にアカウントを作成しておいてください。
まずは、Pusherチャンネルをインストールします。
$ composer require pusher/pusher-php-server
次に、「config/broadcasting.php」の設定ファイルにPusherチャンネルの情報を設定していきます。
PUSHER_APP_ID=your-pusher-app-id
PUSHER_APP_KEY=your-pusher-key
PUSHER_APP_SECRET=your-pusher-secret
PUSHER_APP_CLUSTER=mt1
次に、.envのブロードキャストドライバーをpusherに変更します。
BROADCAST_DRIVER=pusher
これでサーバー側は設定完了です。
次に、クライアント側にLaravel EchoとPusher jsモジュールをインストールします。
$ npm install --save-dev laravel-echo pusher-js
$ npm run dev
これでクライアント側も設定完了です。
イベントクラス作成
イベントはチャンネルを介して、ブロードキャストされますが、チャンネルには以下の2種類があります。
- パブリックチャンネル・・・全ユーザーが購読できるチャンネル
- プライベートチャンネル・・・限定されたユーザーだけが購読できるチャンネル
後ほど説明しますが、プライベートチャンネルでユーザーを限定する方法は、Laravelの認証と認可を使って限定します。これを行うことによって、認証と認可を通過したユーザーのみが購読できるようになります。
それでは、まずはイベントクラスを作成してみます。
$ php artisan make:event BroadcastEvent
それぞれのチャンネルでのイベントクラスを見てみましょう。まずは、パブリックチャンネルです。
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class BroadcastEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $message
/**
* Create a new event instance.
*
* @return void
*/
public function __construct($message)
{
$this->message = $message;
}
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new Channel('notification-channel, $this->message);
}
}
次に、プライベートチャンネルです。
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Database\Eloquent\Model;
// Models
use App\Models\User;
class BroadcastEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $model;
public $user;
/**
* Create a new event instance.
*
* @return void
*/
// 第一引数は通知対象となるユーザー
public function __construct(User $user, Model $model)
{
$this->user = $user;
$this->model = $model;
}
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('notification-channel.' . $this->user->id, $this->model);
}
}
イベントクラスのbroadcastOn()
メソッドの中で、チャンネルを介してブロードキャストを行なっています。パブリックチャンネルの場合はChannel
クラス、プライベートチャンネルの場合はPrivateChannnel
クラスのインスタンスを作成し、返しています。どちらのクラスも、イベントクラスを作成した段階でuse
されているはずですので、介したいチャンネルによってクラスを切り替えるだけですね。
プライベートチャンネルの例では、イベントクラスのインスタンスの第一引数に通知対象のユーザー、第二引数にはブロードキャストしたいデータを渡しています。
また、パブリックチャンネルの場合は全ユーザーにブロードキャストされるので、あとはJavaScript側でイベントをリッスンするだけです。プライベートチャンネルの方は、どんなユーザーに限定してブロードキャストするのかを決めなければいけませんね。
本記事では、プライベートチャンネルでの実装を説明していきます。
次に、認証と認可の設定を行なっていきます。
認証の設定
まずは、config/app.phpのBroadcastServiceProvider
をコメントアウトしておきます。
// config/app.php
'providers' => [
/*
* Laravel Framework Service Providers...
*/
Illuminate\Auth\AuthServiceProvider::class,
Illuminate\Broadcasting\BroadcastServiceProvider::class, // コメントアウト
Illuminate\Bus\BusServiceProvider::class,
Illuminate\Cache\CacheServiceProvider::class,
次に、BroadcastServiceProvider
で認証ルートを設定していきます。
// Providers/BroadcastServiceProvider.php
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Broadcast;
use Illuminate\Support\ServiceProvider;
class BroadcastServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Broadcast::routes(['middleware' => 'auth:api']);
require base_path('routes/channels.php');
}
}
アプリのミドルウェアで設定している認証を使って、ブロードキャストの認証を行います。
認可の設定
次に、認可を設定して購読できるユーザーを限定します。
以下はチャンネル名に含まれるユーザーIDと受信するユーザーのIDが一致しているか、user
はauth
チェックを通っているかの2つを確認しています。
// routes/channels.php
<?php
/*
|--------------------------------------------------------------------------
| Broadcast Channels
|--------------------------------------------------------------------------
|
| Here you may register all of the event broadcasting channels that your
| application supports. The given channel authorization callbacks are
| used to check if an authenticated user can listen to the channel.
|
*/
Broadcast::channel('notification-channel.{id}', function ($user, $id) {
return ((int) $user->id === (int) $id) && auth()->check();
});
イベント発行
イベントを発行したい場所でイベント発行の処理を書きます。
// app/Services/ExternalApi/ReceptionOnPage.php
use App\Events\BroadcastEvent;
foreach ($users as $user) {
if (isset($user)) {
// 第一引数は通知対象のユーザー
event(new BroadcastEvent($user, $tasks));
}
}
イベントをリッスン
最後に、Laravel Echoモジュールを入れてイベントをリッスンします。JavaScript側では、Laravel Echoの初期化を行う必要があります。
プライベートチャンネルの場合は、authEndpoint
を設定します。デフォルトの認証ルートは/Broadcasting/auth
になっており、このルートにアクセスすると、Providers/BroadcastServiceProvider.php
で定義したauth middleware
でauth
を確認しにいきます。
この際、トークンベースの認証方式を採用しているような場合は、ヘッダーにAPI用のトークンをつけないとアクセスできないので注意です。
以下のサンプルコードでは、フロントエンドにVueを採用した場合のコードになっています。
// Laravel Echoを初期化
window.Pusher = require("pusher-js");
window.Echo = new Echo({
broadcaster: "pusher",
key: process.env.pusher.key,
cluster: process.env.pusher.cluster,
encrypted: true,
authEndpoint: process.env.pusher.authUrl,
auth: {
headers: {
authorization: this.getCookieValue("auth._token.local1"),
},
},
});
const userId = this.$store.state.auth.user.id;
// ブロードキャスト通知
window.Echo.private(`notification-channel.${userId}`).listen(
"BroadcastEvent",
(data) => {
console.log(data);
this.broadcastNotifications.push(data.model);
}
);
これでリッスンができるようになります。
実際に、イベントを発行してみてフロント側でページ更新なくリッスンできるか試してみてください。
最後に
いかがでしたでしょうか?
通常、Laravelを用いた開発ではサーバー側とクライアント側で同期的にデータをやり取りしているので、サーバーからレスポンスが返ってくるまでにラグがあったりなどします。
ただ、今回のBroadcastという技術を使うことでリアルタイムにデータのやり取りを行うことができるようになります。
これは非常に面白い技術で、いろいろな用途で利用できるかと思いますので、ぜひお試しください!
ではでは😆
コメント