#24 Laravel基礎
イベントとリスナーでコードを疎結合にする
イベントとリスナーとは
「ユーザーが登録されたとき」というイベントに対して、「ウェルカムメール送信」「ポイント付与」「ログ記録」など複数のリスナーが反応する仕組みです。
コントローラーに全部書くと依存が増えます。イベント・リスナーパターンを使うと、コントローラーは「イベントを発火する」だけでよくなります。
イベントクラスを生成する
php artisan make:event UserRegistered
<?php
// 📁 app/Events/UserRegistered.php
namespace App\Events;
use App\Models\User;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class UserRegistered
{
use Dispatchable, SerializesModels;
public function __construct(
public User $user // ← イベントに含めるデータ
) {}
}
リスナークラスを生成する
php artisan make:listener SendWelcomeEmail --event=UserRegistered
php artisan make:listener AwardSignupPoints --event=UserRegistered
<?php
// 📁 app/Listeners/SendWelcomeEmail.php
namespace App\Listeners;
use App\Events\UserRegistered;
use App\Mail\WelcomeMail;
use Illuminate\Support\Facades\Mail;
class SendWelcomeEmail
{
public function handle(UserRegistered $event): void
{
Mail::to($event->user)->send(new WelcomeMail($event->user));
}
}
<?php
// 📁 app/Listeners/AwardSignupPoints.php
namespace App\Listeners;
use App\Events\UserRegistered;
class AwardSignupPoints
{
public function handle(UserRegistered $event): void
{
$event->user->increment('points', 100); // 登録ポイント付与
}
}
イベントとリスナーを登録する
// 📁 app/Providers/EventServiceProvider.php
protected $listen = [
\App\Events\UserRegistered::class => [
\App\Listeners\SendWelcomeEmail::class,
\App\Listeners\AwardSignupPoints::class,
],
];
Laravel 11以降は AppServiceProvider の boot() で登録もできます。
// 📁 app/Providers/AppServiceProvider.php
use Illuminate\Support\Facades\Event;
public function boot(): void
{
Event::listen(
\App\Events\UserRegistered::class,
\App\Listeners\SendWelcomeEmail::class,
);
}
イベントを発火する
// 📁 app/Http/Controllers/Auth/RegisteredUserController.php
use App\Events\UserRegistered;
public function store(Request $request)
{
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => bcrypt($request->password),
]);
// イベントを発火するだけ!
// SendWelcomeEmail と AwardSignupPoints が自動で動く
UserRegistered::dispatch($user);
return redirect()->route('dashboard');
}
キューと組み合わせる
リスナーに ShouldQueue を実装するだけでキューで非同期実行できます。
// 📁 app/Listeners/SendWelcomeEmail.php
use Illuminate\Contracts\Queue\ShouldQueue;
class SendWelcomeEmail implements ShouldQueue
{
// ...
}
モデルのイベントをディスパッチする
Eloquentモデルのイベントも同じ仕組みで扱えます。
<?php
// 📁 app/Models/Post.php
protected $dispatchesEvents = [
'created' => \App\Events\PostCreated::class,
'deleted' => \App\Events\PostDeleted::class,
];
まとめ
- イベント:何かが起きたことを表すクラス(データを持つ)
- リスナー:イベントに反応して処理を実行するクラス
EventServiceProviderの$listen配列で紐づけを登録するUserRegistered::dispatch($user)でイベントを発火する- リスナーに
ShouldQueueを付けるとキューで非同期実行できる
次回はコマンド(Artisanコマンドの自作)を学びます。