laravel broadcastの使いどころ
一般的なクライアントサーバの仕組みは
クライアントからの要求に対してサーバが応答を返す流れとなる。
サーバ側からクライアント側への逆方向のイベントがないので
サーバ内で発生した変更を知るにはクライントがサーバに対して
定期ポーリングするなどの仕組みが必要だった。
laravelフレームワークではbroadcastという仕組みが用意されており。
websocketサーバを介してサーバからのリアルタイムの変更通知を受信することができる。
前提となる知識としては
backend(laravel)側はLaravelのイベント、リスナー、キューワーカーの知識
frontend(jsvascript)ではWebsocketの知識が前提となる。
Websocketサーバによる外部サービスとしてPusher、ablyなどの無料プランが使えるが
laravel-echoやlaravel-websocketsなどのlaravelフレームワークが用意した
websocketサーバを自前で用意してもよい。その場合はwebscoketサーバの構築の知識が必要になる。
まずは外部サービスpusherjsで実装してみる
pusherjsにてアカウント作成してAPP_KEYを発行する
app_id = "XXXXXX"
key = "yyyyyyyyyyyyyyyyyyyyyy"
secret = "zzzzzzzzzzzzzzzzzz"
cluster = "ap3" // pusherサーバのtimezoneらしい
この値をコピーして.envファイルのPUSHER関連の値を設定する
# BROADCAST_DRIVER=log
BROADCAST_DRIVER=pusherjs
(略)
PUSHER_APP_ID=XXXXXX
PUSHER_APP_KEY=yyyyyyyyyyyyyyyyyyyyyy
PUSHER_APP_SECRET=zzzzzzzzzzzzzzzzzz
PUSHER_APP_CLUSTER=ap3
※以下、websocketサーバ(socketi,laravel-websockets)を自前で用意する場合
laravel(backendとfront)側の設定
laravel(backend)からfrontend(javascript)への橋渡しのライブラリをインストールする。
$ composer require inertiajs/inertia-laravel
front側にinertiaとvueライブラリをインストールする。
$ npm install @inertiajs/inertia @inertiajs/inertia-vue3
front側の大本のファイルは唯一のbladeファイルであるresources/views/app.blade.php
となる。
vueファイルの大本はresources/js/app.js
で
各画面のvueコンポーネントはresources/js/Pages/
配下にvueファイルを格納する構成となる
一覧画面とチャット送信のアクションだけのシンプルなIFのみとする。
一覧画面のURLは/chat
。メッセージの一覧を取得し、画面側に表示する。
送信ボタンでメッセージを登録する。
ここでイベントを使い、同じ画面を見ている別の端末に通知を受信するようにする。
ルーティングは以下の2つ。
Route::get('/chat', 'ChatController@index');
Route::post('/chat', 'ChatController@store');
コントローラでInetriaライブラリつかってページにルーティングする。
(略)
class ChatController extends Controller
{
public function index()
{
return Inertia::render('Chat/Index', [
'messages' => Message::all([
'body', 'created_at'
]);
]);
}
public function store(Request $request)
{
$message = Message::create([
'body' => $request->message,
]);
/* 通知用のイベントをキューに積む */
event(new MessagePostAppended($message));
return redirect()->route('chat.index');
}
}
(略)
MessagePostAppendedがないのでイベントを作成
$ php artisan make:event MessagePostAppended
broadcast機能を使うのでShouldBroadcast
を継承させる。
(略)
class MessagePostAppended implements ShouldBroadcast
{
public $message;
public function __construct(Message $message)
{
$this->message = $message;
}
public function broadcastOn()
{
return new Channel('my-channel');
}
public function broadcastAs()
{
return 'message.appended';
}
}
broadcastOn
が初期値だとPrivateChannelになっているのでChannelクラスに変更。
broadcastAs
でイベント名を任意に設定できる。ない場合はクラス名MessagePostAppended
となる。
このmy-channel
とmessage.appended
(MessagePostAppended
)をfront側で使用する。
front側のjsパッケージをインストールする。
$ npm install --save laravel-echo pusher-js
pusher-js
はpusherjsが提供しているwebsocketライブラリ、
laravel-echo
はlaravelが提供しているWebSocketライブラリで
自前でwebsocket(laravel-echo-serverとかsocket-io)を構築する場合はこちらを利用する。
broadcastの指定でpusherjsもサポートしています。要pusher-js
。
bootsrrap.jsでlaravel-echoインスタンスを生成する。
pusherライブラリもグローバルのPusher
でロードし使えるようにしておく。
(略)
import Echo from 'laravel-echo';
window.Pusher = require('pusher-js');
window.Echo = new Echo({
broadcaster: 'pusher',
key: process.env.MIX_PUSHER_APP_KEY,
cluster: process.env.MIX_PUSHER_APP_CLUSTER,
forceTLS: true,
});
front側はresources\js\Pages\Chat\Index.vue
を作成
broadcastのメッセージを受信したらreloadするようにする
listen
メソッドのイベントの名称は
クラス名の場合はそのままクラス名だがbroadcastAs
で別名を指定した場合は
先頭にピリオドをつけて.message.appended
で待ち受ける。
<script setup>
import { ref } from 'vue';
import BreezeAuthenticatedLayout from '@/Layouts/Authenticated.vue';
import BreezeButton from '@/Components/Button.vue';
import { Inertia } from '@inertiajs/inertia';
import { Head, Link, useForm } from '@inertiajs/inertia-vue3';
defineProps({
messages: Array,
});
const submit = () => {
form.post(route('chat.store'), {
onFinish: () => {
form.reset();
form.message = '';
},
});
};
Echo.channel('my-channel')
.listen('.message.appended', (e) => {
console.log(e);
Inertia.reload();
});
</script>
<template>
<h1>タイトル</h1>
<div v-for="msg in messages">
<span v-text="msg.created_at"></span>:
<span v-text="msg.body"></span>
</div>
<form @submit.prevent="submit">
<textarea v-model="form.message"></textarea><br>
<BreezeButton class="ml-4" :disabled="form.processing">送信</BreezeButton>
</form>
</template>
ここまででWebscoketを外部サービスであるPusherで実装した。
次はこちらをベースに代替フリーウェアのlaravel-websockets
を使用して
ブロードキャスト機能を実装する。