はじめに
今回は、Webアプリケーションに欠かせないリアルタイム通知機能をテーマに、Laravelの強力な機能であるブロードキャストとWebSocketを組み合わせて実装する方法を解説します。バックエンドにRedis、フロントエンドにVue.jsとLaravel Echoを使うことで、シンプルながらも堅牢なシステムを構築します。
なぜWebSocket通信が必要なのか?
Webアプリケーションでリアルタイムなデータ更新が必要な場合、従来は以下のような手法が使われていました。
- ポーリング: クライアントが一定時間ごとにサーバーにリクエストを送り、新しいデータがないかを確認する。これは、サーバーへの無駄なリクエストが増加し、通信コストが高くなるという欠点があります。
- ロングポーリング: サーバーが新しいデータを受信するまでリクエストを保持し、データが届き次第レスポンスを返す。これにより、サーバーリソースを長時間占有するという問題があります。
これに対して、WebSocket通信は、クライアントとサーバー間で一度接続を確立すると、その後は双方向でデータを送受信できる技術です。これにより、サーバーからクライアントへ能動的にデータをプッシュできるようになり、リアルタイムな通信を効率的に実現できます。
Laravelのブロードキャスト機能とWebSocketの仕組み
Laravelには、WebSocket通信を簡単に実装するためのブロードキャスト機能が標準で搭載されています。この機能は、以下のコンポーネントで構成されます。
- Laravel: バックエンドでイベントを発生させ、ブロードキャストドライバ(今回はRedis)を介してWebSocketサーバーにイベントを送信します。
- Redis: リアルタイムイベントのキューとして機能します。Laravelが送信したイベントを一時的に保存します。
- WebSocketサーバー: Redisからイベントを購読し、接続しているクライアント(ブラウザ)にWebSocket経由でデータを送信します。本記事ではlaravel-echo-serverを使用します。
- Laravel Echo: JavaScriptライブラリで、クライアント側でWebSocketサーバーに接続し、イベントを購読する役割を担います。
本記事で構築するリアルタイム通知システムの全体像
本記事では、ユーザーが「いいね」ボタンをクリックすると、以下のフローでリアルタイム通知が送られるシステムを構築します。
ユーザーが「いいね」ボタンをクリックすると、APIリクエストが送信される。
- Laravelがリクエストを受け取り、PostLikedというイベントを発火させる。
- Laravelのブロードキャスト機能が、このイベントをRedisに送信する。
- laravel-echo-serverがRedisからイベントを受け取り、WebSocket通信でフロントエンドに送信する。
- フロントエンドのVue.jsが、Laravel Echoを介してWebSocket通信を受信し、リアルタイムで通知を表示する。
開発環境のセットアップ
Docker Composeを使ったLaravelプロジェクトの準備
まず、Laravelプロジェクトと必要なサービス(Nginx、MySQL、Redis、Node.js)をDockerで動かすためのdocker-compose.ymlを作成します。
YAML
version: '3.8'
services:
app:
build:
context: ./
dockerfile: Dockerfile
volumes:
- .:/var/www/html
ports:
- "8000:8000"
networks:
- app-network
redis:
image: redis:6-alpine
ports:
- "6379:6379"
networks:
- app-network
# Laravel Echo Server用のNode.jsコンテナ
echo-server:
image: node:18-alpine
volumes:
- ./:/app
working_dir: /app
ports:
- "6001:6001"
command: sh -c "npm install && node laravel-echo-server.js start"
depends_on:
- redis
networks:
- app-network
networks:
app-network:
driver: bridge
echo-serverコンテナは、Node.jsベースのWebSocketサーバーであるlaravel-echo-serverを実行するために使用します。
Redisコンテナの追加と設定
LaravelがRedisをブロードキャストドライバとして使用するように設定します。.envファイルを編集します。
BROADCAST_DRIVER=redis
REDIS_HOST=redis
REDIS_HOSTをdocker-compose.ymlで定義したサービス名redisに設定することで、コンテナ間の通信を可能にします。
Laravel Echo Serverの導入と設定
laravel-echo-serverをプロジェクトにインストールします。
Bash
docker-compose exec app npm install -g laravel-echo-server
プロジェクトのルートディレクトリにlaravel-echo-server.jsonファイルを作成し、設定を記述します。
JSON
{
"authHost": "http://localhost:8000",
"authEndpoint": "/api/broadcasting/auth",
"clients": [],
"database": "redis",
"databaseConfig": {
"redis": {
"host": "redis",
"port": "6379"
}
},
"devMode": true,
"host": "0.0.0.0",
"port": "6001",
"protocol": "http"
}
databaseConfigには、Redisコンテナのホスト名(redis)とポート(6379)を指定します。authHostはLaravelアプリケーションのURLです。
バックエンドでのイベント発火とブロードキャスト
通知イベントクラスの作成
Laravelでイベントを定義します。ここでは、「投稿にいいねがされた」というイベントを例にします。
Bash
docker-compose exec app php artisan make:event PostLiked
app/Events/PostLiked.phpに、イベントのプロパティと、ブロードキャストの設定を定義します。
PHP
// app/Events/PostLiked.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 PostLiked implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $user;
public $post;
public function __construct(User $user, Post $post)
{
$this->user = $user;
$this->post = $post;
}
public function broadcastOn(): Channel
{
return new PrivateChannel('notifications.' . $this->post->user->id);
}
public function broadcastWith(): array
{
return [
'message' => "{$this->user->name}さんがあなたの投稿に「いいね」しました!"
];
}
}
ShouldBroadcastインターフェースを実装することで、このイベントがブロードキャスト対象となります。broadcastOn()メソッドでブロードキャストするチャンネルを定義し、broadcastWith()メソッドでブロードキャストするデータを指定します。
ユーザーアクションに応じたイベントの発火
ユーザーが「いいね」ボタンを押した際に、このイベントを発火させます。
PHP
// app/Http/Controllers/PostController.php
use App\Events\PostLiked;
use Illuminate\Http\Request;
public function like(Request $request, Post $post)
{
// いいね処理...
event(new PostLiked($request->user(), $post));
return response()->json(['status' => 'success']);
}
event()ヘルパー関数を使うことで、イベントを簡単に発火させることができます。
プライベートチャンネルでの認証設定
PrivateChannelは、認証されたユーザーのみが購読できるチャンネルです。認証設定を行うために、routes/channels.phpを編集します。
PHP
// routes/channels.php
use Illuminate\Support\Facades\Broadcast;
Broadcast::channel('notifications.{userId}', function ($user, $userId) {
return (int) $user->id === (int) $userId;
});
これにより、認証中のユーザーのIDとチャンネル名に指定されたuserIdが一致する場合にのみ、そのユーザーがチャンネルを購読できるようになります。
フロントエンドでのWebSocket接続と購読
Laravel Echoの初期設定
Vue.jsプロジェクトにlaravel-echoとsocket.io-clientをインストールします。
Bash
npm install laravel-echo socket.io-client --save-dev
resources/js/app.jsでEchoのインスタンスを初期化します。
JavaScript
// resources/js/app.js
import Echo from 'laravel-echo';
import io from 'socket.io-client';
window.io = io;
window.Echo = new Echo({
broadcaster: 'socket.io',
host: window.location.hostname + ':6001'
});
hostには、laravel-echo-serverが動作しているホスト名とポートを指定します。
プライベートチャンネルへの接続
ユーザーがログインしている場合にのみ、プライベートチャンネルを購読します。
JavaScript
const userId = 1; // 認証中のユーザーID
window.Echo.private(`notifications.${userId}`)
.listen('.App\\Events\\PostLiked', (e) => {
console.log('リアルタイム通知:', e);
alert(e.message);
});
.listen()メソッドの第1引数には、イベントクラス名を指定します。broadcastAs()メソッドを使って別名をつけることも可能です。
イベントの受信とリアルタイム通知の表示
イベントを受信すると、.listen()に渡したコールバック関数が実行されます。この関数内で、通知を画面に表示するロジックを実装します。例えば、Vue.jsのコンポーネントで通知一覧に新しい通知を追加する、またはブラウザのネイティブ通知APIを使うなどです。
まとめと応用
構築したシステムのレビューとメリット
本記事で構築したリアルタイム通知システムは、以下のメリットを持っています。
効率的な通信: WebSocketにより、無駄なリクエストをなくし、効率的にリアルタイムなデータ更新が可能。
非同期処理: イベント駆動のアーキテクチャにより、通知処理がメインのHTTPリクエストから切り離され、アプリケーションの応答性が向上。
スケーラビリティ: Redisとキューワーカーを組み合わせることで、トラフィックの増加にも柔軟に対応できる。
通知の永続化と未読管理の実装
このシステムはリアルタイム通知を実装していますが、通知をデータベースに保存し、ユーザーがいつでも確認できるようにすることも重要です。LaravelのNotifications機能は、この永続化と未読管理の機能も提供しています。
- 永続化: databaseドライバを使って通知をデータベースに保存。
- 未読管理: markAsRead()メソッドを使って通知を既読にすることができます。
スケールアウトを見据えたアーキテクチャの検討
本番環境では、laravel-echo-serverの代わりに、より堅牢なプッシャーサービス(例: PusherやLaravel Reverb)を使用することが推奨されます。これらのサービスは、WebSocketサーバーの運用を管理してくれるため、開発者はアプリケーションロジックに集中できます。
- Pusher: サービスとして提供されており、サーバーの管理が不要。
- Laravel Reverb: Laravel公式のWebSocketサーバーで、Laravelのブロードキャスト機能と統合されている。
今回の記事では、LaravelとRedisを使ったWebSocket通信によるリアルタイム通知システムを、Docker環境で構築する方法を解説しました。この知識を活かし、あなたのアプリケーションにユーザーエンゲージメントを高める機能をぜひ実装してみてください。
安心安全のホワイト高還元SESに転職を考えている方へ
新しい挑戦に踏み出すことは、人生において重要な一歩です。 転職活動は自分自身を知り、成長する貴重な機会でもあり、夢や成長を追求するためには必要な要素の一つ になるかと思います。 どんな選択をされるにせよ、その決断があなたに取って素晴らしい未来を切り開くことを願っています! グラディートと一緒に誇れるエンジニアを目指しましょう!
■『株式会社グラディート』では受託開発・SES・ブランディングデザイン・事業コンサルティングなどを事業として行う都内のIT企業です。現在、不遇な待遇で困っているエンジニアさんは、ぜひ一度グラディートに相談してみてね!(年収査定・SESへの転職相談も承っております!)
株式会社グラディート採用情報はこちら▼
https://en-gage.net/gradito/
株式会社グラディート公式サイトはこちら▼
https://www.gradito.co.jp/
