これさえ読めばLaravel Broadcastingの基本が理解できる+Vue.js
目次
LaravelのBroadcastingとは
LaravelのBroadcastingの説明を行う前にイメージ図を使ってLaravel Broadcastingを理解しておきましよう。
下記の図のように真ん中にあるLaravelサーバはテレビ局の電波塔のように地域全体に電波が飛ばすように情報を送信します。Laravelサーバから送信された情報は送信されてくるのを待ち受けているブラウザによって受け取れます。サーバが特定のブラウザを指定して情報を送信しているわけではなく不特定多数のブラウザに向けて送信しているのでBroadcastingと呼ばれます。テレビとは異なりブラウザはいつも情報が送信されてくるのを待っているわけでなくブラウザからサーバに対して処理の依頼を行うこともできます。ブラウザから依頼を受けた処理がサーバ上で終了したあとに送信される更新情報にもBroadcastingが使われることもあります。
各家庭で好きな番組を視聴する際にチャンネルを合わせて受信するようにLaravelサーバにアクセスしている各ブラウザもチャネルを設定してLaravelからの情報を受信します。WebSocketという技術を使ってブラウザをリロードすることなくリアルタイムで受け取った情報をブラウザ上に描写することができます。
LaravelのBroadcastingにはPusherとRedisという2つ方法が準備されています。今回の説明ではPusherを用いた方法でBroadcastingの動作確認を行います。
Pusherを利用した場合のBroadcastingを図にすると以下のようになります。Laravelからブラウザに直接データが送信されるわけではなく、LaravelのEventを利用してPusherにデータを送信し、Pusherを経由してブラウザに情報が渡されます。渡されたデータはJavaScriptを使ってブラウザをリロードすることなくブラウザに反映することができます。
一度にすべての動作を確認するより3つのパートに順を追って説明したほうが理解しやすいため以下の3つのパートにわけて説明を行なっていきます。1と2でLaravelサーバから送られたデータがブラウザに届くまでの流れを理解することができます。3では送られたデータをVue.jsを使ってブラウザをリロードすることなしにブラウザに反映させる方法を確認します。
- LaravelからEventを使い、Pusherにデータを送信、Pusherが受信
- Pusherから送られたデータをブラウザで受信
- Laravel→Pusher→ブラウザにきたデータをVue.jsを使い描写
LaravelからPusherへのデータ送信
Laravelのバージョンは6.0を利用しています。
Laravelのインストール
まず最初にLaravelのインストールを行います。
$ composer create-project --prefer-dist laravel/laravel laravel_echo
JavaScriptライブラリを利用するので、npmのインストールを行います。
$ cd laravel_echo
$ npm install
Broadcastingの設定
Broadcastingの機能はデフォルトでは使えないようになっているので使えるように関連するファイルを更新していきます。
Laravelのインストールが完了したら、configディレクトリにあるapp.phpファイルを開いてコメントされているBroadcastServiceProviderのコメントを外します。
・
・
App\Providers\AuthServiceProvider::class,
App\Providers\BroadcastServiceProvider::class, //ここがコメントされている
App\Providers\EventServiceProvider::class,
・
・
次にconfigディレクトリにあるbroadcastingの設定ファイルbroadcasting.phpを開いて、設定されているドライバの確認を行います。デフォルトではnullになってるので、.envファイルでどのドライバが使われているか確認します。.envファイルはLaravelインストールディレクトリに保存されています。
'default' => env('BROADCAST_DRIVER', 'null'),
.envファイルを見るとlogに設定されています。Broadcastingが動作するか確認するために最初はlog設定のままで進めます。
BROADCAST_DRIVER=log
イベントの作成
Broadcatingで送信するデータはイベント経由で行います。
イベントの知識がなくても動作確認は行えますが、Laravelのイベントがどのような機能だったか確認したい場合は下記を参考にしてください。
イベントの作成は、php arisan make:eventコマンドで行います。タスクが追加されたという情報を送信したいので、イベント名はTaskAddedとします。
$ php artisan make:event TaskAdded
Event created successfully.
app¥EventsディレクトリにTaskAdded.phpファイルが作成されます。Broadcastingの設定を行うのでTaskAdded.phpファイルを開きます。Broadcastingを行うためにTaskAddedクラスにShouldBroadcastインターファイスを継承させる必要があります。
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class TaskAdded implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
ShouldBroadcastインターファイスの中にはbroadcastOnメソッドのみ記述されています。
namespace Illuminate\Contracts\Broadcasting;
interface ShouldBroadcast
{
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|\Illuminate\Broadcasting\Channel[]
*/
public function broadcastOn();
}
作成したTaskAddedにもbroadcastOn()メソッドが実装されています。PrivateChannelを使っていますが、Channelクラスに変更します。チャネル名をtask-added-channelに変更します。
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
変更後はbroadcastOnメソッドは下記のようになります。
public function broadcastOn()
{
return new Channel('task-added-channel');
}
web.phpを開いて、/tasksルーティングを追加し、作成したTaskAddedイベントを下記のようにeventヘルパー関数で発行させます。ブラウザで”/tasks”にアクセスするとTaskAddedイベントが発行されます。
use App\Events\TaskAdded;
Route::get('/tasks', function () {
event(new TaskAdded);
});
Broadcastingの初期動作確認
php artisan serveコマンドで開発サーバを起動します。
$ php artisan serve
Laravel development server started: <http://127.0.0.1:8000>
ブラウザを使ってサーバにアクセスします。アクセスしたあとにstorage/logsの下にあるログファイルを開いてください。.envファイルのbroadcastのドライバをlogに設定していたので、ログファイルに下記の情報が書き込まれます。
[2019-09-08 01:03:26] local.INFO: Broadcasting [App\Events\TaskAdded] on channels [task-added-channel] with payload:
{
"socket": null
}
イベント名と設定したチャネル名を確認することができればここまで設定したBroadcastingの設定は問題なく行われています。
Pusherのアカウント登録
Pusherを利用するためにはアカウント登録を行う必要があります。Pusher.comにアクセスして、Sign up for freeボタンをクリックします。
アカウント情報の入力画面が表示されるので、Github、Googleアカウントもしくはメールアドレスを入力します。
メールアドレスを入力した場合は下記のアカウント認証画面が表示されます。メールがPusherから届いているのでメールを確認してアカウント認証を行います。
アカウント認証が完了するとアプリケーションの名前をつける画面が表示されるので、任意の名前をつけてください。select a clusterではap3(Asia Pacific(Tokyo))に設定します。設定が完了したら、Create my appボタンをクリックしてください。ここでは名前をtestにしました。
アプリケーションの作成が完了するとクライアント側、サーバ側で使用している言語やフレームワークを選択できる画面が表示されます。今回はクライアント側でLaravel Echo、サーバ側でLaravelを使用するのでタブでそれぞれを選択してください。
変更するとクライアント側でインストールしなければならないJavaScriptライブラリと受信用のコード、サーバ側ではインストールしなければならないPHPパッケージでPusherの接続に必要なAPI KEYの情報が表示されます。
Pusherに接続するためのAPP KeysはApp Keysタグからも確認することができます。
Pusher設定(Laravel側)
Pusherを使用するためのAPP Keysの情報が入手できたので、設定を行なっていきます。まず、Pusherを利用するために必要なパッケージをcomposerを使ってインストールします。
$ composer require pusher/pusher-php-server
pusherパッケージのインストールが完了したら、.envファイルを開いてPusher接続用の情報を設定します。
PUSHER_APP_ID=856176
PUSHER_APP_KEY=0a3d15b7980b0719ae17
PUSHER_APP_SECRET=fb9e693d112c6c64267f
PUSHER_APP_CLUSTER=ap3
.envファイルのBROADCAST_DRIVERをlogからpusherに変更します。
BROADCAST_DRIVER=pusher
Pusher側でLaravelから送られてくる情報を確認するためにDebug Consoleを開きます。
設定はすべて完了したので、ブラウザからhttp://localhost:8000/tasksにアクセスしてPusherに情報が届くのか確認します。
PusherのDebug Console画面にチャネル名とイベント名が表示されたら、Pusherへのメッセージ送信が正常に動作しています。
Pusherに追加データを送信する
先ほどはPusherにはデータが届きましたが、チャンネル名とイベント名以外の情報がなかったので、Pusherに送信する情報に追加データをつけてみましょう。
変数$taskを作成し配列でidとnameを持たせます。
Route::get('/tasks', function () {
$task = ['id' => 1, 'name' => 'メールの確認'];
event(new TaskAdded($task));
});
TaskAddedイベントファイルで$taskをPusherに送る設定を行います。
class TaskAdded implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $task;
public function __construct($task)
{
$this->task = $task;
}
public function broadcastOn()
{
return new Channel('task-added-channel',$this->task);
}
}
再度、ブラウザで/taskにアクセスしましょう。PusherのDebug Consoleに追加したtaskの情報が表示されたら、情報の追加も正常に行われています。
Pusherからのデータをブラウザで受信
LaravelからPusherへデータが送信できることを確認しました。次は、Pusherが受け取ったデータをブラウザ側で表示されるための設定を行います。Laravel Echoを利用して受信を行うので、2つのJavaScriptライブラリのインストールを行います。
JavaScriptライブラリのインストール
npmコマンドでlaravel-echoとpusher-jsライブラリをインストールします。
$ npm install --save laravel-echo pusher-js
LaravelではJavaScriptファイルを更新するとコンパイルが必要となります。ファイルの更新を監視できるようにnpm run watchコマンドを実行します。
$ npm run watch
JavaScriptファイルの更新
インストールしたlarave-echoとpusher-jsライブラリに関する記述はでデフォルトではコメントされているので、コメントを外す必要があります。
resource¥js¥bootstrap.jsを開いてコメントされている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,
encrypted: true
});
上記のMIX_PUSHER_APP_KEYとMIX_PUSHER_APP_CLUSTERは.envファイルの中で設定が行われています。Pusherからのデータを受け取るためには、クライアントであるブラウザ側ではAPP_KEYとAPP_CLUSTERの2つが必要であることがわかります。
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
Bladeファイルの更新
クライアントであるブラウザ側でデータを受信するということはLaravelにアクセスするブラウザが表示するBladeファイルでデータを受け取るためのコードを記述する必要があります。
受信の動作確認を行うためにwelcome.blade.phpファイルを使用します。
welocome.blade.phpファイルを開いてapp.jsファイルをscriptタグで読み込みます。
<script src="/js/app.js"></script>
</body>
また、Laravel EchoではCSRFトークンを利用するのでmetaタグを追加する必要があります。
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>Laravel</title>
ここまでの設定でPusherからのデータの受信は行えませんが、Pusherへの接続設定が完了したwelcome.blade.phpを開くとPusherへ接続が行われることを確認することができます。
LaravelからデータをPusherに送信する設定が完了し、クライアントであるブラウザがPusherに接続することが確認できました。最後に必要なのは、ブラウザがPusherからデータを受け取ることなのでその設定を行います。
JavaScriptファイルでの受信設定
次にPusherからのメッセージが受け取れるようにするためにbootstrap.jsで追加設定を行う必要があります。channelメソッドにはイベントTaskAddedで設定したチャネル名、listenメソッドには、イベント名を指定します。Pusherからのデータはdataに入ってくるので、console.logコマンドでコンソールにメッセージでPusherから送られてくるデータを表示させます。
window.Echo.channel('task-added-channel')
.listen('TaskAdded',function(data){
console.log('received a message');
console.log(data);
});
まず、ブラウザを開いて”/”ルートにアクセスを行います。
上記のチャネルとイベントを設定する前は、”/”にアクセスしても2行の情報しか表示されませんでしたが、新たにSubscribed等チャネルに関する追加情報が表示されています。
次に別のブラウザを開いて/taskにアクセスを行います。/taskにアクセスしたのでpusherに向けてLaravelから情報が送信されます。
ブラウザのコンソールを開いてみるとConsoleにメッセージとPusherから受け取ったtaskの情報が表示されていることが確認できます。データを受け取る際はブラウザのリロード等は必要ありません。
ここまでの流れを通して、LaravelからPusherへのデータの送信、Pusherへのクライアントの接続(ブラウザ)とPusherからのデータの受け取りを確認することができました。
“/”ルートにアクセスするブラウザ1つだけで動作確認を行いましたが、同時に複数のブラウザで”/”を表示している時に別のブラウザで”/tasks”にアクセスすると”/”にアクセスしているすべてのブラウザでPusherからの情報を受け取ることができます。
[付録]Laravel Echoライブラリを使用しない場合
npmコマンドでLaravel Echoライブラリのインストールを行いましたが、Laravel Echoを使用しない場合でもPusherからのデータの受け取りを確認しておきましょう。
bootstrap.jsで設定したいたlaravel-echoと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,
// encrypted: true
// });
// window.Echo.channel('task-added-channel')
// .listen('TaskAdded',function(data){
// console.log('received a message');
// console.log(data);
// });
次にwelcome.blade.phpにpusherのライブラリをcdnで読み込み、Pusherからのデータ受け取りのコードを記述します。設定はチャネルとイベント、PusherのAPI Key情報を入れるだけです。
<script src="https://js.pusher.com/5.0/pusher.min.js"></script>
<script>
// Enable pusher logging - don't include this in production
Pusher.logToConsole = true;
var pusher = new Pusher('0a3d15b7980b0719ae17', {
cluster: 'ap3',
forceTLS: true
});
var channel = pusher.subscribe('task-added-channel');
channel.bind('TaskAdded', function(data) {
console.log('received a message');
console.log(data);
});
</script>
1つのブラウザで”/”ルートにアクセスし、もう一つのブラウザで”/tasks”にアクセスすると下記のようにPusherからのデータを確認することができます。
Pusherのロギングモードにしているので、Pusherとの接続やWebsocketの情報も表示されます。
Vue.jsを使ってデータを表示
vue.jsを使って受け取ったデータをブラウザに表示される方法を確認します。Todoリストを表示するプログラムを作成し、新たにTodoを追加すると、その一覧を表示しているすべてのブラウザ上でTodoの追加が行われます。
Vueライブラリの設定
Laravelでvue.jsに利用できるようにvue.jsに関する設定を追加します。
vue.jsを追加するためにlaravel/uiパッケージをインストールする必要があります。
$ composer require laravel/ui
php artisanコマンドを利用して、vue.jsだけではなく認証機能(本文書では使用しない)も合わせて追加します。
$ php artisan ui vue --auth
Vue scaffolding installed successfully.
Please run "npm install && npm run dev" to compile your fresh scaffolding.
Authentication scaffolding generated successfully.
php artisanコマンド実行後に下記のnpmコマンドを実行します。JavaScriptのライブラリのインストールを行い、JavaScriptファイルのコンパイルを行なっています。
$ npm install && npm run dev
次にTodoリストのデータを保存するためにデータベースを作成します。
データベースの接続
データを保存するためにはデータベースを作成する必要があります。簡易的に作成できるsqliteデータベースを使用します。
Laravelのインストールディレクトリの下にあるdatabaseディレクトリにdatabase.sqliteファイルを作成します。
$ touch database/database.sqlite
.envファイルを開いてDB_CONNECTIONをデフォルトのmysqlからsqliteに変更し、DB_CONNECTION以外のDB設定のパラメータを削除します。
DB_CONNECTION=sqlite
これでデータベースの設定は完了なので、php artisan migrateコマンドを実行し、認証に使用するusersテーブルが作成できるか確認します。
$ php artisan migrate
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_000000_create_users_table (0.02 seconds)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated: 2014_10_12_100000_create_password_resets_table (0 seconds)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated: 2019_08_19_000000_create_failed_jobs_table (0 seconds)
上記のようにテーブルの作成に成功したら、データベースへの接続設定も問題なく行われています。
tasksテーブルの作成
todoリストを保存するためにtodosテーブルを使用します。php arisanコマンを使ってmigrationファイルとTodo.phpファイルを作成します。
$ php artisan make:model Todo -m
Model created successfully.
Created Migration: 2019_09_08_112219_create_todos_tabl
テーブルの構造はname列を追加だけのシンプルなものです。
public function up()
{
Schema::create('todos', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->timestamps();
});
}
php artisan migrateコマンドでtodosテーブルを作成します。
$ php artisan migrate
Migrating: 2019_09_08_112219_create_todos_table
Migrated: 2019_09_08_112219_create_todos_table (0.02 seconds)
Todo.phpファイルを開いてname列の設定を行います。
namespace App;
use Illuminate\Database\Eloquent\Model;
class Todo extends Model
{
protected $fillable = ['name'];
}
todoの各種設定
web.phpにtodosに関するルーティングを追加します。ブラウザから”/todos”にアクセスするとTodoリストの一覧が表示されます。
Route::get('/todos', function(){
return view('todos.index');
});
resources¥viewsの下にtodosディレクトリを作成し、index.blade.phpファイルを作成します。
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>Todos</title>
</head>
<body>
<div id="app">
<todos-list></todos-list>
</div>
<script src="/js/app.js"></script>
</body>
</html>
<todos-list></todos-list>のvue.jsのコンポーネントでtodosをリスト化を行う部分です。後ほど作成します。JavaScriptの/js/app.js、csrf_tokenは忘れずに追加してください。
vueコンポーネントの作成
Pusherから受け取ったデータを描写する部分なのでここからが重要になります。
コンポーネントtodos-listのための設定を行うため、resources¥js¥app.jsファイルを開いてください。
下記の行がデフォルトで設定されていますが、ExapleComponentは使用しないので、TodoListCompomentに変更します。
Vue.component('example-component', require('./components/ExampleComponent.vue').default);
[変更後]
Vue.component('todos-list', require('./components/TodoListComponent.vue').default);
resources¥js¥componentsの下にTodoListComponent.vueを作成します。
axiosを利用して、todosテーブルからリストを取得して、表示するコードを作成します。
<template>
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<h1>Todoリスト</h1>
<ul>
<li v-for="todo in todos">{{ todo['name'] }}</li>
</ul>
</div>
</div>
</div>
</template>
<script>
export default {
data(){
return {
todos : []
}
},
mounted(){
axios.get('/api/todos').then(response => (this.todos = response.data));
},
}
</script>
routes¥api.phpファイルを開いて、axiosで/api/todosにアクセスがあった場合にtodoリストを戻すルーティングを追加します。
Route::get('/todos',function(){
return \App\Todo::all();
});
ブラウザで/todosにアクセスした時に下記の画面が表示されます。
まだtodoテーブルにはデータが登録されていないのでリストには何も表示されません。
input要素の追加
Todoリストにデータを追加できるようにinput要素を追加します。v-modelでnewTodoプロパティを設定し、blurイベントを設定し、addTodoメソッドを設定します。
<input type="text" v-model="newTodo" @blur="addTodo">
JavaScript側の追加を行います。
export default {
data(){
return {
todos : [],
newTodo : ''
}
},
mounted(){
axios.get('/api/todos').then(response => (this.todos = response.data));
},
methods:{
addTodo(){
axios.post('/api/todos',{
name : this.newTodo
})
.then(response => this.todos.push(response.data));
this.newTodo = '';
}
}
}
axiosのPOSTリクエストで送ったデータをtodosテーブルに追加できるようにroutes¥api.phpに新たにルーティングを追加します。
Route::post('/todos',function(){
$todo = \App\Todo::create(request()->all());
return $todo;
});
ブラウザで/todosにアクセスしてinput要素に追加したTodoがリストに表示されていくことを確認してください。
ここまでの確認
todosにアクセスして、input要素にTodoを入力するとvue.jsの設定により、入力したブラウザではブラウザをリロードすることなくTodoリストに項目が追加されていきます。しかし、別のブラウザで/todosにアクセスしてもアクセスした時点でのTodoリストの一覧は取得できますが、その後別のブラウザでTodoを追加してもそのブラウザには追加は反映されません。ブラウザをリロードして初めて他のブラウザで追加された値がTodoリストに反映されます。
イベントの作成
Todoリストが作成されたという情報をPusherに送るためにイベントの作成を行います。
$ php artisan make:event TodoAdded
Event created successfully.
app¥eventsの下にTodoAdded.phpファイルが作成されます。チャネル名はto-added-channelという名前で$todoを一緒にPusherに送信します。
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class TodoAdded implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $todo;
public function __construct($todo)
{
$this->todo = $todo;
}
public function broadcastOn()
{
return new Channel('to-added-channel',$this->todo);
}
}
イベントはTodoリストを追加した時に発行されるので、routes¥api.phpにイベントのコードを追加します。
Route::post('/todos',function(){
$todo = \App\Todo::create(request()->all());
event((new todoAdded($todo));
return $todo;
});
上記のイベントを追加したので、Todoリストを追加したら、Pusherに追加したTodoの情報が送信されることになります。”/todos”にアクセスしてTodoを追加してみましょう。
Pusherに上記のように追加の情報が表示されたらLaravelからPusherへの送信は正常に動作しています。
Pusherから情報を受け取る
Pusherからデータを受け取り、Todoリストに追加したTodoをリアルタイムで表示されるようにTodoListCompomentコンポーネントを更新します。
window.Echoの部分を追加しており、channelにはTodoAddedで設定したチャネル、listeneにはTodAddedのイベント名を設定します。Pusherから受け取ったデータはtodosのリストに追加しています。
export default {
data(){
return {
todos : [],
newTodo : ''
}
},
mounted(){
axios.get('/api/todos').then(response => (this.todos = response.data));
window.Echo.channel('todo-added-channel')
.listen('TodoAdded',response => {
this.todos.push(response.todo);
});
},
methods:{
addTodo(){
axios.post('/api/todos',{
name : this.newTodo
})
.then(response => this.todos.push(response.data));
this.newTodo = '';
}
}
}
/todosにアクセスして、Todoリストを追加するとaddTodoメソッドで追加した分とPusherから受け取った分の2行が一度に追加されます。
入力を行なったブラウザには先ほど説明した理由で2行の情報が表示されます。Pusherからの更新が入力を行なったブラウザ上で行われないように設定する必要があります。routes¥api.phpを開いて、dontBroadcastToCurrentUserメソッドをevent関数に下記のように追加します。
event((new TodoAdded($todo))->dontBroadcastToCurrentUser());
設定を行なったあと、Todoに追加すると1行しか追加が行われなくなります。また、別のブラウザを開いている場合は、Todoを追加すると別のブラウザでもTodoへ追加した内容がリストに追加されることが確認できます。
別のブラウザの画面です。
特にvue.jsと組み合わせたブラウザの表示では説明が長くなりましたが、Pusherから受け取ったデータをリアルタイムにリロードなしで追加されることが確認できました。
Private Channelを設定する
ここまで設定したChannelはPublic Channelでだれでもこのチャネルから情報を取得することができました。ここではユーザ認証を利用することでチャネルへのアクセスを制限を行うPrivate Channelの動作確認を行います。
テーブルへの列追加
todosテーブルに新たにuser_idの列を追加します。user_idを追加し設定を行うことでtodoリストを作成したユーザのみPusherからの情報を受け取れるようになります。
todosテーブルのマイグレーションファイルを開いてuser_idを追加します。
public function up()
{
Schema::create('todos', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('user_id');
$table->string('name');
$table->timestamps();
});
}
php artisan migration:refreshコマンドを使用してテーブルを再作成します。
$ php artisan migrate:refresh
user_idにデータが挿入できるようにTodo.phpを開いて下記の$fillable変数にuser_idを追加してください。
protected $fillable = ['name','user_id'];
ユーザ登録
Private Channelではユーザ認証を利用するためシステムへのユーザ登録を行います。
テーブルの登録部分の変更
todosテーブルに新たにuser_idを追加したのでリスト追加のプログラムを変更する必要があります。
これまではデータ登録時にnameのみ必要でしたが今後はuser_idが必要になります。このuser_idはシステムにログインしている認証済みのユーザ情報です。
methods:{
addTodo(){
axios.post('/api/todos',{
name : this.newTodo,
user_id : //ここにuser_idが必要
})
.then(response => this.todos.push(response.data));
this.newTodo = '';
}
}
views¥todos¥index.htmlファイルを開いてscriptタグの中で認証ユーザの情報を取得します。認証済みユーザの場合のみ情報が取得できる設定です。
<script> window.user = {!! auth()->user() !!}; </script>上記でユーザ情報が取得できるので、addTodoメソッド内のuser_idは下記のように記述することができます。
axios.post('/api/todos',{
name : this.newTodo,
user_id : user_id : window.user['id']
})
Private Channelへの設定変更
これまではテーブルとユーザに関する設定変更でしたが、ここではChannelからPrivate Channelへの変更を行います。
TodoAddedイベントのTodoAdded.phpファイルを開いてChannelからPrivateChannelに変更します。さらにチャネル名にIDをつけます。
public function broadcastOn()
{
return new PrivateChannel('todo-added-channel.'.$this->todo->user_id);
}
次にTodolistComponent.vueファイルを開きます。
windows.Echoのchannelメソッドをprivateメソッドに変更し、チャネル名にユーザのIDをつけます。これでTodoAddedで設定したチャンネル名と同じ形になります。
window.Echo.private('todo-added-channel.' + window.user['id'])
.listen('TodoAdded',response => {
this.todos.push(response.todo);
});
最後にroutes¥channels.phpファイルを開いてチャネルの設定を行います。$user変数には、ログインしているユーザの情報が入り$idには、TodolistComponent.vueファイルで設定したwindow.user[‘id’]の値が入ることになります。下記の設定では認証済みのユーザのみtodo-added-channel.{userId}のチャネルを受け取ることができます。
Broadcast::channel('todo-added-channel.{userId}', function ($user, $id) {
return (int) $user->id === (int) $id;
});
todoリストを追加した場合にTodoAddedイベントが発行されますが、チャネル名は、’todo-added-channel.’.$this->todo->user_idになっているので、todoリストを追加したユーザのみがPusherから送られてくるデータを受け取ることができます。
Pusher上での確認
PusherでのDebug Consoleを見ながら流れを確認していきましょう。
作成したユーザでログインを行い、/todosにアクセスをすると
Channel: private-todo-added-channel.1でSUBSCRIBEDされていることがわかります。
Todoリストへの追加を行います。
追加を行うとイベントが発生するのでPusherに情報が送信されます。送信されたチャネル名を見るとChannel:private-todo-added-channel.1になっていることがわかります。Subcribedした時と同じチャネル名を持っているのでこのユーザにはPusherからの情報を受け取ることができます。
もし、IDの異なるユーザでログインを行うと異なるチャネル名になります。Channel:private-todo-added-channel.2になっています。チャネル名が異なるので、Channel:private-todo-added-channel.1からの情報を受け取ることができません。
このようにPrivate Channelではチャネル名とユーザ認証を使ってPusherからのデータを受け取れるユーザを制限しています。
認証されていないユーザでのログイン
システムに登録されていないユーザでログインを行うと下記のuser情報が取得できないので値なしのエラーが発生します。
<script> window.user = {!! auth()->user() !!}; </script>ゲストユーザでもアクセスできるシステムではauth()->check()などを使ってゲストユーザの場合は値なし等の設定を行う必要があります。
ここまで読み終えた方はPusherを使用したLaravel Broadcastingの基本が理解できたと思います。