laravel5.7で、リアルタイムチャットや通知に必要なpusher.comを使ってみた
リアルタイムチャットや通知には、サーバ側からブラウザ側へアクションをしないとダメなのだが、そもそもHTTPはブラウザ側からの一期一会のアクションしか存在しない(郵便ポストに投函して返事を待つイメージ)
GET(このファイルくれ!)→index.html
POST(このデータでなんとかして!)→index.html(申し込みフォームや検索など)
なので、node.jsなどを使ってWebSocket(電話のようにつなげっぱなしな状態)を利用しないと、phpではリアルタイムチャットや通知を実現できない!
一番最初の下準備として、PusherのPHP SDK, Laravel Echo(ブロードキャスト/WebSocket)をインストールする
1 2 |
composer require pusher/pusher-php-server npm install --save laravel-echo pusher-js |
pusher.comのアカウントとCreate new app(laravel+JS)を作ったら、Getting Startedに、受信処理(HTML)と送信処理(PHP)があるので、そのままコピペすれば、laravelでpusher送受信が出来る
routes/web.php(空文字の部分は、各自のIDやKEYが入力されているはず!)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
<?php // pusherからの受信処理 Route::get('/receive', function() { // Getting Startedの左側のjavascript受信処理(HTML)をコピペ return <<<EOF <!DOCTYPE html> <head> <title>Pusher Test</title> <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('', { cluster: '', forceTLS: true }); var channel = pusher.subscribe('my-channel'); channel.bind('my-event', function(data) { alert(JSON.stringify(data)); }); </script> </head> <body> <h1>Pusher Test</h1> <p> Try publishing an event to channel <code>my-channel with event name <code>my-event</code>. </p> </body> EOF; }); // pusherへの送信処理 Route::get('/send', function(){ // pusherの左側のPHPタブの送信処理をコピペ $options = array( 'cluster' => '', 'useTLS' => true ); $pusher = new Pusher\Pusher( '', '', '', $options ); $data['message'] = 'hello world'; $pusher->trigger('my-channel', 'my-event', $data); }); |
/receiveのページを開いた状態で、/sendのページにアクセスすると、pusher.com経由で、/receiveページにalertが表示される!!
これはこれで簡単だけど、あちこちに同じ処理を書くのは大変なので、laravelのお作法に沿って記述する。
0, config/app.phpで、なぜかブロードキャストだけコメントアウトされているので、コメントインする
1 |
Illuminate\Broadcasting\BroadcastServiceProvider::class, |
1, .envに、pusher.comへのアクセス情報を記述。これでlaravelからpusherへアクセス出来るようになる。
1 2 3 4 5 6 7 8 |
#logからpusherに変更 BROADCAST_DRIVER=pusher # pusher.comのApp Keysに同じ順番で書いてあるのでコピペ PUSHER_APP_ID= PUSHER_APP_KEY= PUSHER_APP_SECRET= PUSHER_APP_CLUSTER= |
2, チャット用のMessageモデルを作る
1 2 3 4 5 6 7 |
# チャット用メッセージモデル・コントローラー・マイグレーション・ダミーデータを生成。 php artisan make:model Message --all # app/Message.phpに、レコード書き込みのため protected $guarded = ['id']; しておく # messageテーブルに、$table->text('text');だけ追加 # チャットのメッセージ作成イベントを生成 php artisan make:event MessageCreated |
3, Eloquentには、最初からCRUD操作する時にpusherに通知する機能がある!
Laravel 5.1 Broadcastig EventsでPusherを利用してリアルタイム更新アプリを作成するには
4, app/Providers/AppServiceProvider.phpに、チャットで発言されたら、イベント発火するように記述
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
use Event; use App\Message; use App\Events\MessageCreated; class AppServiceProvider extends ServiceProvider { public function boot() { // チャットで発言されたら、発火 Message::created(function ($message) { // laravel5.8でfire廃止、event()に置き換える。 //Event::fire(new MessageCreated($message)); event(new MessageCreated($message)); }); } |
5, Messageレコードを新規作成されたら、pusher通知を行うようにする。
※pusher通知の書き込み(event)には、channel名, event名, app_id, key, secret, clusterが必須!
pusher通知の読み込み(listener)には、channel名, event名, app_id, clusterが必須!(key, secretは不要)
同じapp_id内で、channel名やevent名で通知を使い分ける。
app/Events/MessageCreated.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
<?php namespace App\Events; use App\Message; // チャットのメッセージ 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; // implements ShouldBroadcastを追加しないとpusherへ送信されない。 class MessageCreated implements ShouldBroadcast { use Dispatchable, InteractsWithSockets, SerializesModels; // このイベント(messageレコード新規作成)が発火したら、メッセージ文字列を受け取り、pusherへ投げる(このレコードの全カラム情報) // レコード更新・削除にもイベント追加できる。AppServiceProviderのboot()にも記述する public $message; public function __construct(Message $message) { $this->message = $message; } // チャンネル名を設定 public function broadcastOn() { return new Channel('my-channel'); } // イベント名を設定 public function broadcastAs() { return 'my-event'; } } |
6, resources/views/index.blade.phpなどに、受信処理(HTML)をコピペしておく
最初の/receiveを利用しても良い。
7, 適当なルーティングで、Messageレコード新規作成して、受信処理(HTML)が正常に動作するか確認する。
1 2 3 4 5 6 7 8 9 |
Route::get('/write', function () { App\Message::create(['text'=>'hello']); return 'ok'; }); Route::get('/', function () { return view('index'); }); |
これで、なんとなくpusher(リアルタイム通知)が使えるようなった(画面周りは何も作っていないのでサンプルのアラート表示のまま)ので、次はプライベート・イベント(ログインした特定のユーザ向け)を実装してみよう。
今回のは、パプリック・イベントなので、ログインとか無関係だった。