【Laravel】Pusherを使ってリアルタイムにイベントを更新する


# 今回作るもの

こちらの[チュートリアル](https://pusher.com/docs/channels/getting_started/javascript-realtime-chart)を参考に、サーバで発行したイベントの結果をリアルタイムにチャートで表現します。

![ezgif-3-4c1f7bfa07ce.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391127/e06dd594-1965-e2d9-1d17-f49258b6f70a.gif)

[JavaScript realtime chart quick start](https://pusher.com/docs/channels/getting_started/javascript-realtime-chart)


# 環境
PHP: 7.2.5
Laravel: 7.0
pusher-php-server: 4.1

# Pusher Appの作成

[こちらの記事](https://qiita.com/akkino_D-En/items/9d6e49c5f7aa41e31021#pusher%E3%81%A7app%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B)を参考にAppを作成してください。

# チャートページの作成

[チュートリアルのページ](https://pusher.com/docs/channels/getting_started/javascript-realtime-chart#create-your-webpage)を参考（ほぼコピペ）に[Google Charts](https://developers.google.com/chart)を使用してチャートUIを作成します。

```html:resources/views/realtime-chart.blade.php
<html>
    <body>
        <div id="chart_div" style="width: 100%; height: 500px;"></div>
        <script src="https://www.gstatic.com/charts/loader.js"></script>
        <script src="https://js.pusher.com/5.1/pusher.min.js"></script>
        <script>
            google.charts.load('current', {'packages': ['corechart']});
            google.charts.setOnLoadCallback(() => {
                // Instead of hard-coding the initial table data,
                // you could fetch it from your server.
                const dataTable = google.visualization.arrayToDataTable([
                    ['Year', 'Price'],
                    [2013, 400],
                    [2014, 460],
                ]);
                const chart = new google.visualization.AreaChart(
                    document.getElementById('chart_div'));
                const options = {
                    title: '1 BTC in USD',
                    hAxis: {title: 'Year', titleTextStyle: {color: '#333'}},
                    vAxis: {minValue: 0},
                    animation: {duration: 100, easing: 'out'}
                };
                chart.draw(dataTable, options);
                let year = 2015;
                Pusher.logToConsole = true;
                const pusher = new Pusher("{{ config('const.pusher.app_key') }}", { // Replace with 'key' from dashboard
                    cluster: "{{ config('const.pusher.cluster') }}",              // Replace with 'cluster' from dashboard
                    forceTLS: true
                });
                const channel = pusher.subscribe('price-btcusd');
                channel.bind('new-price', data => {
                    const row = [year++, data.value];
                    dataTable.addRow(row);
                    chart.draw(dataTable, options);
                });
            });
        </script>
    </body>
</html>
```

この時Pusherの引数に直接`APP_KEY`や`APP_CLUSTER`の値を入れずに定数などを作成するようにしましょう。

このページでは`price-btcusd`チャンネルの`new-price`イベントを待機しています。
イベントが発生すると`value`フィールドが抽出され、新しいデータとしてグラフに追加されます。

最後にこのページへのルーティングを設定すれば完了です。

```php:routes/web.php
Route::get('/realtime-chart', function () {
    return view('realtime-chart');
});
```


# サーバーからイベントを発行する

イベントを受け取るページを作成したので、今度はイベントを発行する処理を作成しましょう。

まずPusherのライブラリを追加します。

```
composer require pusher/pusher-php-server
```

`.env`にPusherアプリの設定を記載します。
アプリのキーは`Getting Started`のサンプル内、または`App Keys`タブに記載されているのでそちらを参照してください。

```:.env
PUSHER_APP_ID=12345
PUSHER_APP_KEY=hoge-app-key
PUSHER_APP_SECRET=hoge-app-secret
PUSHER_APP_CLUSTER=hoge-cluster
```

またこれを呼び出すための定数を作成します。

```php:config/const.php
return [
    'pusher' => [
        'app_id' => env('PUSHER_APP_ID'),
        'app_key' => env('PUSHER_APP_KEY'),
        'app_secret' => env('PUSHER_APP_SECRET'),
        'cluster' => env('PUSHER_APP_CLUSTER'),
    ]
];
```


`config/app.php`に`Pusher`を追加します。

```php:config/app.php
return [
    ...
    'aliases' => [
        ...
        'Pusher' => Pusher\Pusher::class,
    ]
]
```

実際にイベントを発行する処理を実装します。

```php
namespace App;

use Pusher\Pusher;

class RealtimeChartEvent
{
    public function run()
    {
        $pusher = new Pusher(
            config('const.pusher.app_key'),
            config('const.pusher.app_secret'),
            config('const.pusher.app_id'),
            array(
                'cluster' => config('const.pusher.cluster')
            )
        );

        $i = 0;

        // 毎秒新しいランダムな値をvalueに含めたイベントを発行する
        // 実際に使用する場合は毎秒では無く、データの変更をトリガーにしてイベントを発行してください
        while (true) {
            $pusher->trigger('price-btcusd', 'new-price', array(
                'value' => rand(0, 5000)
            ));

            // 何回イベントを発行したかを確認するために追加
            $i ++;
            echo('send ' . $i . ' times' . PHP_EOL);

            sleep(1);
        }
    }
}
```

# 動作確認

* 作成したチャートのページを開きます。（http://localhost:10080/realtime-chart）

* `tinker`を開き、先ほど作成したイベントを実行します。（永久ループするので終了する場合はcontrol + c）

```
$ php artisan tinker

>>> $event = new App\Events\RealtimeChartEvent();
>>> $event->run();
```

* 実行ログが流れ、チャートがリアルタイムに動作したら成功です。

![ezgif-3-4c1f7bfa07ce.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391127/a3348ad5-02a2-8546-641a-e3c9263899c4.gif)


```
send 1 times
send 2 times
send 3 times
send 4 times
send 5 times
...
```

## Pusherのダッシュボードでイベントを確認

Pusherのダッシュボードから`Channels`→アプリを選択→`Overview`を開くと、作成したAppにどれぐらいのconnectionとmessageが送られたかを確認することができます。

<img width="1192" alt="スクリーンショット 2020-06-14 16.41.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391127/f80d82f7-4d24-461d-ec81-e1004ae471eb.png">


## 参考資料
[JavaScript realtime chart quick start](https://pusher.com/docs/channels/getting_started/javascript-realtime-chart)
[【Laravel】Pusherを使ってみる](https://qiita.com/akkino_D-En/items/9d6e49c5f7aa41e31021#pusher%E3%81%A7app%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B)
[Pusher公式ドキュメント](https://pusher.com/docs)
[Class 'Pusher\Pusher' not found #26](https://github.com/pusher/pusher-http-laravel/issues/26)