🤩
Laravel 12で管理者通知システムを実装する
概要
新規ユーザー登録やメール認証完了時に、管理者宛に自動で通知メールを送信するシステムを実装しました。この記事では、Laravel 12のイベントシステム、通知機能、重複送信防止など、実装した全ての要素を初心者にも分かりやすく解説します。
実装した機能
- 新規ユーザー登録時に管理者に通知メール送信
- メール認証完了時に管理者に通知メール送信
- 重複送信防止機能
- 非同期処理(キュー)対応
目次
Laravelのイベントシステムとは
イベントとは?
イベントとは、アプリケーション内で「何かが起こった」ことを表す仕組みです。例えば:
- ユーザーが新規登録した
- メール認証が完了した
- 注文が確定した
これらの「出来事」をイベントとして定義し、その出来事が発生した時に自動で処理を実行できます。
イベントの仕組み
ユーザー登録 → Registeredイベント発火 → リスナーが実行 → 管理者に通知メール送信
Laravel 12でのイベント登録方法
Laravel 12では、bootstrap/app.phpでイベントを登録する方法と、従来のEventServiceProviderを使う方法があります。今回は後者を採用しました。
通知クラスの作成
通知クラスとは?
通知クラスは、メールやSMSなどの通知を送信するための専用クラスです。LaravelのNotificationクラスを継承して作成します。
新規登録通知クラス
<?php
namespace App\Notifications;
use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
class AdminNewUserRegistered extends Notification implements ShouldQueue
{
use Queueable;
public function __construct(private readonly User $user)
{
}
public function via(object $notifiable): array
{
return ['mail'];
}
public function toMail(object $notifiable): MailMessage
{
$user = $this->user;
return (new MailMessage)
->subject('[AWSの中学校] '.$user->name.' さんが新規登録しました')
->greeting('新規登録のご連絡')
->line($user->name.' さんが新規登録しました。')
->line('メールアドレス: '.$user->email)
->line('登録日時: '.now()->toDateTimeString())
->salutation('AWSの中学校');
}
}
コード解説
1. クラス定義
class AdminNewUserRegistered extends Notification implements ShouldQueue
-
Notificationを継承:Laravelの通知機能を使う -
ShouldQueueを実装:非同期処理(キュー)で実行
2. コンストラクタ
public function __construct(private readonly User $user)
-
private readonly:PHP 8.1の機能で、プロパティを自動で定義 - ユーザー情報を受け取って保存
3. 通知方法の指定
public function via(object $notifiable): array
{
return ['mail'];
}
-
viaメソッドで通知方法を指定 -
['mail']:メール通知のみ - 他にも
['database'](DB保存)、['slack'](Slack通知)など
4. メール内容の定義
public function toMail(object $notifiable): MailMessage
{
$user = $this->user;
return (new MailMessage)
->subject('[AWSの中学校] '.$user->name.' さんが新規登録しました')
->greeting('新規登録のご連絡')
->line($user->name.' さんが新規登録しました。')
->line('メールアドレス: '.$user->email)
->line('登録日時: '.now()->toDateTimeString())
->salutation('AWSの中学校');
}
-
MailMessage:Laravelのメールビルダー -
subject():件名を設定 -
greeting():挨拶文を設定 -
line():本文の行を追加 -
salutation():署名を設定
認証完了通知クラス
<?php
namespace App\Notifications;
use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
class AdminEmailVerified extends Notification implements ShouldQueue
{
use Queueable;
public function __construct(private readonly User $user)
{
}
public function via(object $notifiable): array
{
return ['mail'];
}
public function toMail(object $notifiable): MailMessage
{
$user = $this->user;
return (new MailMessage)
->subject('[AWSの中学校] '.$user->name.' さんのメール認証が完了しました')
->greeting('メール認証完了のお知らせ')
->line($user->name.' さんがメール認証を完了しました。')
->line('これで学習コンテンツにアクセスできるようになりました。')
->line('メールアドレス: '.$user->email)
->line('認証完了日時: '.now()->toDateTimeString())
->line('学習を開始する準備が整いました!')
->salutation('AWSの中学校');
}
}
イベントリスナーの作成
リスナーとは?
リスナーは、イベントが発生した時に実行される処理を定義するクラスです。イベントを「聞いて」、指定した処理を実行します。
新規登録リスナー
<?php
namespace App\Listeners;
use App\Notifications\AdminNewUserRegistered;
use Illuminate\Auth\Events\Registered;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Facades\Cache;
class NotifyAdminOfNewRegistration implements ShouldQueue
{
public function handle(Registered $event): void
{
$user = $event->user;
$cacheKey = 'admin_notification_sent_' . $user->id;
// 5分以内に同じユーザーからの通知が送信済みの場合はスキップ
if (Cache::has($cacheKey)) {
return;
}
$adminEmail = config('admin.register_notify_email');
if (! $adminEmail) {
return;
}
Notification::route('mail', $adminEmail)
->notify(new AdminNewUserRegistered($user));
// 通知送信済みをキャッシュに記録(5分間)
Cache::put($cacheKey, true, now()->addMinutes(5));
}
}
コード解説
1. クラス定義
class NotifyAdminOfNewRegistration implements ShouldQueue
-
ShouldQueue:非同期処理で実行
2. handleメソッド
public function handle(Registered $event): void
-
Registered $event:Laravelの新規登録イベント - イベントが発生すると自動でこのメソッドが呼ばれる
3. 重複防止機能
$user = $event->user;
$cacheKey = 'admin_notification_sent_' . $user->id;
// 5分以内に同じユーザーからの通知が送信済みの場合はスキップ
if (Cache::has($cacheKey)) {
return;
}
-
$event->user:イベントからユーザー情報を取得 -
$cacheKey:ユーザーIDベースのキャッシュキーを作成 -
Cache::has():キャッシュに存在するかチェック - 存在する場合は処理をスキップ(重複送信防止)
4. 管理者メールアドレスの取得
$adminEmail = config('admin.register_notify_email');
if (! $adminEmail) {
return;
}
-
config('admin.register_notify_email'):設定ファイルから管理者メールアドレスを取得 - 設定されていない場合は処理をスキップ
5. 通知送信
Notification::route('mail', $adminEmail)
->notify(new AdminNewUserRegistered($user));
-
Notification::route():特定の宛先に通知を送信 -
new AdminNewUserRegistered($user):通知クラスのインスタンスを作成
6. キャッシュ記録
Cache::put($cacheKey, true, now()->addMinutes(5));
- 通知送信済みをキャッシュに記録
- 5分間の有効期限を設定
認証完了リスナー
<?php
namespace App\Listeners;
use App\Notifications\AdminEmailVerified;
use Illuminate\Auth\Events\Verified;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Facades\Cache;
class NotifyAdminOfEmailVerification implements ShouldQueue
{
public function handle(Verified $event): void
{
$user = $event->user;
$cacheKey = 'admin_verification_notification_sent_' . $user->id;
// 5分以内に同じユーザーからの認証完了通知が送信済みの場合はスキップ
if (Cache::has($cacheKey)) {
return;
}
$adminEmail = config('admin.register_notify_email');
if (! $adminEmail) {
return;
}
Notification::route('mail', $adminEmail)
->notify(new AdminEmailVerified($user));
// 通知送信済みをキャッシュに記録(5分間)
Cache::put($cacheKey, true, now()->addMinutes(5));
}
}
EventServiceProviderの設定
EventServiceProviderとは?
イベントとリスナーを紐付ける設定ファイルです。どのイベントが発生した時に、どのリスナーを実行するかを定義します。
<?php
namespace App\Providers;
use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Events\Verified;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use App\Listeners\NotifyAdminOfNewRegistration;
use App\Listeners\NotifyAdminOfEmailVerification;
class EventServiceProvider extends ServiceProvider
{
/**
* The event to listener mappings for the application.
*
* @var array<class-string, array<int, class-string>>
*/
protected $listen = [
Registered::class => [
NotifyAdminOfNewRegistration::class,
],
Verified::class => [
NotifyAdminOfEmailVerification::class,
],
];
/**
* Register any events for your application.
*/
public function boot(): void
{
//
}
}
コード解説
1. イベントとリスナーのマッピング
protected $listen = [
Registered::class => [
NotifyAdminOfNewRegistration::class,
],
Verified::class => [
NotifyAdminOfEmailVerification::class,
],
];
-
Registered::class:新規登録イベント -
Verified::class:メール認証完了イベント - 配列形式で複数のリスナーを登録可能
2. プロバイダーの登録
bootstrap/app.phpでEventServiceProviderを登録:
->withProviders([
EventServiceProvider::class,
])
重複送信防止機能
なぜ重複送信が起こる?
- イベントの重複発火:同じイベントが複数回発火する
- キュー処理の重複:同じジョブが複数回実行される
- ユーザーの重複操作:同じ操作を複数回実行する
解決方法:キャッシュベースの重複チェック
$cacheKey = 'admin_notification_sent_' . $user->id;
// 5分以内に同じユーザーからの通知が送信済みの場合はスキップ
if (Cache::has($cacheKey)) {
return;
}
// 通知送信処理...
// 通知送信済みをキャッシュに記録(5分間)
Cache::put($cacheKey, true, now()->addMinutes(5));
キャッシュキーの設計
-
新規登録:
admin_notification_sent_{ユーザーID} -
認証完了:
admin_verification_notification_sent_{ユーザーID}
有効期限の設定
- 5分間:短すぎると通知が届かない、長すぎると重複防止が効かない
- 必要に応じて調整可能
設定ファイルの作成
管理者設定ファイル
<?php
return [
'register_notify_email' => env('ADMIN_REGISTER_NOTIFY_EMAIL'),
];
.envファイルの設定
# 管理者通知メールアドレス
ADMIN_REGISTER_NOTIFY_EMAIL=設定したいメールアドレス
設定の取得方法
$adminEmail = config('admin.register_notify_email');
-
config('admin.register_notify_email'):設定ファイルから値を取得 -
.envファイルで上書き可能 - デフォルト値を設定可能
実際の動作フロー
新規登録時の流れ
1. ユーザーが新規登録
↓
2. Registeredイベントが発火
↓
3. NotifyAdminOfNewRegistrationリスナーが実行
↓
4. 重複チェック(キャッシュ確認)
↓
5. 管理者に通知メール送信
↓
6. 送信済みをキャッシュに記録
メール認証完了時の流れ
1. ユーザーがメール認証リンクをクリック
↓
2. Verifiedイベントが発火
↓
3. NotifyAdminOfEmailVerificationリスナーが実行
↓
4. 重複チェック(キャッシュ確認)
↓
5. 管理者に通知メール送信
↓
6. 送信済みをキャッシュに記録
送信されるメール内容
新規登録通知
- 件名: 「[アプリ名] 田中太郎 さんが新規登録しました」
- 内容: 登録日時、メールアドレス
認証完了通知
- 件名: 「[アプリ名] 田中太郎 さんのメール認証が完了しました」
- 内容: 認証完了日時、学習開始準備完了のメッセージ
まとめ
実装した機能
-
イベントベースの通知システム
- Laravelのイベントシステムを活用
- 新規登録とメール認証完了で自動通知
-
重複送信防止
- キャッシュベースの重複チェック
- 5分間の有効期限で確実に1通のみ送信
-
非同期処理
- キューを使用した非同期送信
- ユーザー体験を損なわない
-
設定の外部化
-
.envファイルで管理者メールアドレスを管理 - 環境ごとに異なる設定が可能
-
技術的なポイント
- イベントリスナー: イベント駆動型の設計
- 通知クラス: 再利用可能な通知機能
- キャッシュ: 重複防止とパフォーマンス向上
- キュー: 非同期処理によるUX向上
今後の拡張可能性
- 複数宛先への通知: 配列形式で複数の管理者に送信
- 通知方法の追加: Slack、SMS、プッシュ通知など
- 通知内容のカスタマイズ: テンプレート化による柔軟な内容変更
- 通知履歴の管理: データベースに通知履歴を保存
この実装により、管理者は新規ユーザーの登録状況をリアルタイムで把握でき、適切なフォローアップが可能になります。
Discussion