LaravelとWebSocket：リアルタイムアプリケーションの作成

# はじめに
こんにちは、Webエンジニアの岩田史門([@SI_Monxy](https://x.com/SI_Monxy))です！
今回はLaravelとWebSocketについて記事を書いてみました！
改善点や修正点があれば、コメントにて優しくご指導いただけると嬉しいです！

# 概要
リアルタイム通信を実現するための技術としてWebSocketがあります。WebSocketは、クライアントとサーバー間で双方向の通信を可能にし、HTTPプロトコルよりも効率的にリアルタイムデータの送受信を行えます。この記事では、LaravelとWebSocketを使用してリアルタイムアプリケーションを構築する方法をステップバイステップで説明します。

# 環境設定
まず、Laravelプロジェクトを作成し、必要なパッケージをインストールします。

``` bash
composer create-project --prefer-dist laravel/laravel websocket-app
cd websocket-app
composer require beyondcode/laravel-websockets
```

次に、laravel-websocketsパッケージをインストールします。

``` bash
php artisan vendor:publish --provider="BeyondCode\LaravelWebSockets\WebSocketsServiceProvider" --tag="migrations"
php artisan migrate
php artisan vendor:publish --provider="BeyondCode\LaravelWebSockets\WebSocketsServiceProvider" --tag="config"
```

# WebSocketサーバーのセットアップ
config/websockets.phpファイルを開き、WebSocketサーバーの設定を行います。

``` php
return [

    'apps' => [
        [
            'id' => env('PUSHER_APP_ID'),
            'name' => env('APP_NAME'),
            'key' => env('PUSHER_APP_KEY'),
            'secret' => env('PUSHER_APP_SECRET'),
            'path' => env('PUSHER_APP_PATH'),
            'capacity' => null,
            'enable_client_messages' => true,
            'enable_statistics' => true,
        ],
    ],

    'ssl' => [
        'local_cert' => env('LARAVEL_WEBSOCKETS_SSL_LOCAL_CERT', null),
        'local_pk' => env('LARAVEL_WEBSOCKETS_SSL_LOCAL_PK', null),
        'passphrase' => env('LARAVEL_WEBSOCKETS_SSL_PASSPHRASE', null),
    ],

    'statistics' => [
        'model' => \BeyondCode\LaravelWebSockets\Statistics\Models\WebSocketsStatisticsEntry::class,
    ],

];
```

次に、.envファイルにPusherのキーを追加します。

``` env
PUSHER_APP_ID=your-app-id
PUSHER_APP_KEY=your-app-key
PUSHER_APP_SECRET=your-app-secret
PUSHER_APP_CLUSTER=mt1
```

# LaravelとWebSocketの統合
BroadcastServiceProviderを有効にし、WebSocketを使用するために必要な設定を行います。

``` php 
// config/app.php

'providers' => [
    ...
    App\Providers\BroadcastServiceProvider::class,
    ...
];
```

次に、routes/channels.phpファイルにチャンネルを追加します。

``` php
Broadcast::channel('chat', function ($user) {
    return Auth::check();
});
```

# クライアントサイドの実装
クライアント側でWebSocketを使用するために、EchoとPusher JavaScriptライブラリをインストールします。

``` bash
npm install --save laravel-echo pusher-js
```

次に、resources/js/bootstrap.jsファイルを編集してEchoを設定します。

``` js
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,
});
```

# サンプルアプリケーション
簡単なチャットアプリケーションを作成してみましょう。まず、イベントを作成します。

``` bash
php artisan make:event MessageSent
```

app/Events/MessageSent.phpを編集して、メッセージイベントを定義します。

``` php
namespace App\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

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

    public $message;

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

    public function broadcastOn()
    {
        return new Channel('chat');
    }

    public function broadcastWith()
    {
        return ['message' => $this->message];
    }
}
```

次に、コントローラーを作成してメッセージを送信します。

``` bash
php artisan make:controller ChatController
```

app/Http/Controllers/ChatController.phpを編集します。

``` php
namespace App\Http\Controllers;

use App\Events\MessageSent;
use Illuminate\Http\Request;

class ChatController extends Controller
{
    public function sendMessage(Request $request)
    {
        $message = $request->input('message');
        event(new MessageSent($message));
        return response()->json(['status' => 'Message Sent!']);
    }
}
```

最後に、フロントエンドでメッセージを送信し、受信するコードを追加します。

``` html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Chat</title>
    <script src="{{ mix('js/app.js') }}"></script>
</head>
<body>
    <div id="app">
        <input type="text" id="message" placeholder="Enter your message">
        <button onclick="sendMessage()">Send</button>
        <ul id="messages"></ul>
    </div>

    <script>
        function sendMessage() {
            const message = document.getElementById('message').value;
            fetch('/send-message', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
                },
                body: JSON.stringify({ message })
            });
        }

        window.Echo.channel('chat')
            .listen('MessageSent', (e) => {
                const messages = document.getElementById('messages');
                const messageItem = document.createElement('li');
                messageItem.textContent = e.message;
                messages.appendChild(messageItem);
            });
    </script>
</body>
</html>
```

# まとめ
この記事では、Laravelを使用してWebSocketを実装し、リアルタイムアプリケーションを作成する方法について解説しました。WebSocketを活用することで、ユーザーによりインタラクティブな体験を提供できます。

# 参考
- [Laravel WebSockets Documentation](https://laravel.com/docs/11.x/broadcasting)
- [Pusher Documentation](https://pusher.com/docs/)