LoginSignup

This article is a Private article. Only a writer and users who know the URL can access it.
Please change open range to public in publish setting if you want to share this article with other users.

More than 5 years have passed since last update.

Laravel5.7でBroadcastingをPusherで利用する

Last updated at Posted at 2018-12-07

LaravelでBroadcasting(Echo)を利用する場合、laravel-echo-serverを利用する方法とpusherを利用する方法があります。
laravel-echo-serverを利用する場合、別途redisの構築も必要になるなど、めんどくさいので、今回はpusherを利用する方法を試してみます。

Pusherの準備

まずはPusherから。

アカウント作成

アカウントがない場合は作成します。
無料で1日100connection(同時接続数), 20万配信までできるようです。

App作成

アカウントができたら、アプリケーションを作成します。
アイコンでfrant-endとしてJSを、backendとしてLaravelを選んでおきます。

  • front-end : JS(Vanilla JS)
  • back-end : Laravel

アプリケーションが生成されたら、App Keys情報を確認しておきます(これを.envに設定します)。
Pusher側の設定はこれだけ。

Laravel(環境設定)

続いてLaravel側でPusherを利用する設定を行います。

ライブラリのインストール

pusherの利用に必要なライブラリをインストールします。

composer require pusher/pusher-php-server

.env(抜粋)

必要な変数を設定します。

BROADCAST_DRIVER=pusher

下記はPusherのApp Keysで確認できる値となります。

PUSHER_APP_ID=6xxxxx
PUSHER_APP_KEY=9695e12b43abxxxxxxxx
PUSHER_APP_SECRET=0ae47e5a9448xxxxxxxx
PUSHER_APP_CLUSTER=apx

config/app.php(抜粋)

app.phpの下記の行をコメントインします。

App\Providers\BroadcastServiceProvider::class,

Laravel(Eventの実装)

Eventファイルの作成

下記コマンドを実行してEventを作成します。app/Events以下にファイルが生成されます。

なお、イベント(Channel)の種類には全員に配信するパブリックチャネルと特定のクライアントに配信するプライベートチャネルがありますが、とりあえずパブリックチャネルを実装してみます。

php artisan make:event PublicEvent

Eventの実装

以下の用に記述します。

app/Events/PublicEvent
<?php

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 PublicEvent implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public function __construct()
    {
        //
    }

    public function broadcastOn()
    {
+        return new Channel('public-event');
    }

+    public function broadcastWith()
+    {
+        return [
+            'message' => 'PUBLIC',
+        ];
+    }
}

ルートの追加

Eventの発火は任意のタイミングで行えますが、今回は特定のURLにアクセスしたら発火するようにします。
/public-eventにアクセスするとイベントが発火します。

Route::get('/public-event', function(){
    broadcast(new \App\Events\PublicEvent);
    return 'public';
});

サーバ側の実装は以上です。

Laravel(クライアント側の実装)

続いてクライアント側です。

なお、個人的なゴールはReactNativeからの利用なのでここでは最低限の実装しかしません。すみません。

ライブラリのインストール

npm install --save laravel-echo pusher-js

bootstrap.js

とりあえずresources/js/bootstrap.jsの最後を以下の用にします。既にpusherのための記述がされているのでコメントインして、サーバ側で設定したEvent(Channel)を購読するコードを追加します。

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('public-event')
    .listen('PublicEvent', (e) => {
        console.log(e);
    })

app.js

以下の記述はいらないのでコメントアウトしておきます。

// const app = new Vue({
//     el: '#app'
// });

周辺ライブラリのインストールとコンパイル

npm install && npm run devして、コンパイルします。

npm install
npm run dev

welcome.blade.phpの編集(表示)

配信された情報を表示しています。今回はconsole.log()でbroadcastWith()で送られてきたオブジェクト内容を表示するだけです。
そのために元々存在するwelome.blade.phpに以下の記述を追加します。

csrf tokenの追加

購読の認証の際にcsrf tokenが必要らしいのでtokenを連携できるよう記述します。

<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
+<meta name="csrf-token" content="{{ csrf_token() }}">

(bootstrap.jsとかに書いた)jsの呼び出し

先程書いたjsがコンパイルされた結果のapp.jsを参照するための記述を追加します。

+<script src="{{ asset('js/app.js')}}"></script>
</body>

動作確認

Laravelの起動(購読側)

serveして、トップページ(welcome.blade.php)を開き、デバッグコンソールを開いてきます。

php artisan serve

Eventの発火

http://localhost:8000/public-event にアクセスしてEventを発火させます。

Console画面の確認

PUBLICと表示されていればOKです。

Private-Channel

では続いてPrivate-Channelの実装を行ってみます。

認証機能の追加

Private-ChannelではLaravelで認証された特定のユーザーに対する配信となるので、まずは認証を実装します。
また、認証方法としてはAPI経由での認証を利用します。

Userのマイグレーションファイルを以下のように変更してmigrateします。

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateUsersTable extends Migration
{
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
+            $table->string('api_token')->unique()->nullable();
        });
    }

    public function down()
    {
        Schema::dropIfExists('users');
    }
}

migrate。既にmigrateしてる場合はrefreshします。

php artisan migrate

tinkerを利用して認証で利用するユーザーを追加しておきます。

php artisan tinker

>>> $user = new App\User;
=> App\User {#2907}
>>> $user->name = 'user1';
=> "user1"
>>> $user->email = 'user1@test.com';
=> "user1@test.com"
>>> $user->password = Hash::make('testtest');
=> "$2y$10$pN7.zZyJ87zgusHvkjkMv.bnFyT/g174WTi7kMzezES8V5KWPMGp."
>>> $user->api_token = 'user1user1';
=> "user1user1"
>>> $user->save();
=> true

認証方法の変更

デフォルトではBroadcast用のAPIにはWebミドルウエアが適用されるのでAPIミドルウエアが適用されるように変更します。
app/Providers/BroadcastServiceProvider.phpを以下のように変更します。

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Broadcast;

class BroadcastServiceProvider extends ServiceProvider
{
    public function boot()
    {
+        Broadcast::routes(['middleware' => 'auth:api']);
        require base_path('routes/channels.php');
    }
}

PrivateEventの追加

Private用のEventを生成します。

php artisan make:event PrivateEvent

PrivateEvent

とりあえず以下のように実装します。

<?php

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 PrivateEvent implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public function __construct()
    {
        //
    }

    public function broadcastOn()
    {
+        return new PrivateChannel('private-event');
    }

    public function broadcastWith()
    {
        return [
+            'message' => 'PRIVATE',
        ];
    }
}

routes/channel.php

Private-Channelではchannel.phpでルート毎に認証を実装する必要がありますが、ここでは一旦trueを返し、常に認証OKとします。

Broadcast::channel('private-event', function () {
    return true;
});

routes

Private-Eventを発火させるルートを定義します。

もちろん、発火はルートへのアクセスである必要がありません。

Route::get('/private-event', function(){
    broadcast(new \App\Events\PrivateEvent);
    return 'private';
});

bootstrap.js(抜粋)

クライアント側の処理として、private-eventを購読するよう設定します。

window.Echo.connector.pusher.config.auth.headers['Authorization'] = 'Bearer user1user1';
window.Echo.connector.pusher.config.auth.headers['Accept'] = 'application/json';
window.Echo.connector.pusher.config.authEndpoint = 'http://localhost:8000/broadcasting/auth';
window.Echo.private('private-event')
    .listen('PrivateEvent', (e) => {
        console.log(e);
    });

動作確認

ここまでで一度動作を確認してみます。
/private-eventにアクセスし、welcome.blade.phpのコンソールにPRIVATEと表示させるか確認します。

PrivateChannelの改善

PublicとPrivate-Channelが使えるようになりましたが、上記の実装では全員がprivate-eventという同じイベントを購読するため機能的にPublicと変わりありません。
ユーザー毎に異なったChannelを購読するよう変更します。

Eventの引数に$userを渡す。

Route::get('/private-event', function(){
    //user1を取得
    $user = App\User::find(1);
    //userを渡す
    broadcast(new \App\Events\PrivateEvent($user));
    return 'private';
});

チェネル名をprivate-channel.user_idとなるよう変更

<?php

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;

use App\User;

class PrivateEvent implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $user;

    public function __construct(User $user)
    {
        $this->user = $user;
    }

    public function broadcastOn()
    {
        return new PrivateChannel('private-event.' . $this->user->id);
    }

    public function broadcastWith()
    {
        return [
            'message' => 'PRIVATE',
        ];
    }
}

channel.phpで簡易認証を行う

Broadcast::channel('private-event.{id}', function ($user, $id) {
    return (int) $user->id === (int) $id;
});

クライアント側でもprivate-channel.user_idのChannelを購読する

const user_id = 1;
window.Echo.connector.pusher.config.auth.headers['Authorization'] = 'Bearer user1user1';
window.Echo.connector.pusher.config.auth.headers['Accept'] = 'application/json';
window.Echo.connector.pusher.config.authEndpoint = 'http://localhost:8000/broadcasting/auth';
window.Echo.private('private-event.' + user_id.toString())
    .listen('PrivateEvent', (e) => {
        console.log(e);
    });

以上。

0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up