バージョン
- Laravel 11
- PHP 8.3
デフォルトの挙動
まずデフォルトのnotificationsテーブルへのデータ保存 + メール送信が動くようにします。
php artisan make:notifications-table
コマンドで通知データを保存するためのmigrationファイルが作成できます。
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('notifications', function (Blueprint $table) {
$table->uuid('id')->primary();
$table->string('type');
$table->morphs('notifiable');
$table->text('data');
$table->timestamp('read_at')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('notifications');
}
};
UserモデルはNotifiableトレイトを利用する必要があります。
class User extends Authenticatable
{
+ use Notifiable;
usersテーブルとは別のテーブルにメールアドレスを保存している場合は、routeNotificationForMailメソッドをUserモデルに作成する必要があります。
class User extends Authenticatable
{
use Notifiable;
+ public function routeNotificationForMail(): array|string
+ {
+ // usersテーブルではなくrelation先のprofilesテーブルにメールアドレスを保存している場合など
+ return $this->profile->email;
+ }
php artisan make:notification TestNotification
で通知用のクラスを作成します。
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
class TestNotification extends Notification
{
use Queueable;
/**
* Create a new notification instance.
*/
public function __construct()
{
//
}
/**
* Get the notification's delivery channels.
*
* @return array<int, string>
*/
public function via(object $notifiable): array
{
- return ['mail'];
+ return ['database', 'mail'];
}
/**
* Get the mail representation of the notification.
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->line('The introduction to the notification.')
->action('Notification Action', url('/'))
->line('Thank you for using our application!');
}
/**
* Get the array representation of the notification.
*
* @return array<string, mixed>
*/
public function toArray(object $notifiable): array
{
return [
//
];
}
}
あとは任意のUserモデルを取得しnotifyメソッドを実行するとnotificationsテーブルにデータが保存されるとともにメールが送信されます。
/** @var User $user */
$user = User::find($id);
$user->notify(new TestNotification());
notifications
id | type | notifiable_type | notifiable_id | data | read_at | created_at | updated_at |
---|---|---|---|---|---|---|---|
591dd764-5a26-42ff-b71c-2815d01aded3 | App\Notifications\TestNotification | App\Models\User | 1 | [] | NULL | 2024-06-10 18:10:21 | 2024-06-10 18:10:21 |
テーブル&カラムの変更
以下のようにnotifications
テーブルをuser_notifications
テーブルに変更、不要なカラムも削除します。
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('user_notifications', function (Blueprint $table) {
$table->uuid('id')->primary();
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->morphs('notifiable');
$table->text('data');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('user_notifications');
}
};
モデル作成
php artisan make:model UserNotification
でモデルを作成しDatabaseNotificationクラスを継承しテーブル名を設定します。
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Notifications\DatabaseNotification;
-class UserNotification extends Model
+class UserNotification extends DatabaseNotification
{
use HasFactory;
+ protected $table = 'user_notifications';
}
Userモデルのnotificationメソッドを作成します。
public function notifications()
{
return $this->morphMany(UserNotification::class, 'notifiable')->latest();
}
デフォルトのnotificationsメソッドはnotifiableトレイトのさらにHasDatabaseNotificationsトレイトにあります。
trait HasDatabaseNotifications
{
/**
* Get the entity's notifications.
*
* @return \Illuminate\Database\Eloquent\Relations\MorphMany
*/
public function notifications()
{
return $this->morphMany(DatabaseNotification::class, 'notifiable')->latest();
}
CustomDatabaseChannelの作成
php artisan make:channel CustomDatabaseChannel
コマンドでCustomDatabaseChannelを作成しbuildPayloadメソッドをオーバーライドします。
第1引数の$notifiableはnotifiableトレイトを使用しているUserモデルのインスタンスが渡されます。第2引数はnotifyメソッドの引数で渡したNotificationクラスが渡されます。
<?php
namespace App\Broadcasting;
use App\Models\User;
use App\Notifications\TestNotification;
use Illuminate\Notifications\Channels\DatabaseChannel;
use Illuminate\Notifications\Notification;
class CustomDatabaseChannel extends DatabaseChannel
{
/**
* @param User $notifiable
*/
protected function buildPayload($notifiable, TestNotification|Notification $notification): array
{
return [
'id' => $notification->id,
'user_id' => $notifiable->id,
'data' => $this->getData($notifiable, $notification),
];
}
}
TestNotificationクラスで作成したデータはtoArrayメソッド(もしくはtoDatabaseメソッド)を通して、CustomDatabaseChannelクラスのgetDataメソッドを使用して取得することができます。(https://laravel.com/docs/11.x/notifications#formatting-database-notifications)
public function toArray(object $notifiable): array
{
return [
'key' => '任意の値',
];
}
protected function buildPayload($notifiable, TestNotification|Notification $notification): array
{
// toArrayの返り値をgetDataメソッドで取得することができる
$data = $this->getData($notifiable, $notification);
TestNotificationクラスのviaメソッドのdatabaseをCustomDatabaseChannelに書き換えます。
public function via(object $notifiable): array
{
- return ['database', 'mail'];
+ return [CustomDatabaseChannel::class, 'mail'];
}
以上でデフォルトのnotificationsテーブルとは異なるテーブルにデータを保存することができるようになりました。
user_notifications
id | user_id | notifiable_type | notifiable_id | data | created_at | updated_at |
---|---|---|---|---|---|---|
89dd877f-c637-4728-a292-76ce5a5beb5b | 1 | App\Models\User | 1 | [] | 2024-06-10 18:52:59 | 2024-06-10 18:52:59 |
user_notificationsテーブルのnotifiable_type、notifiable_idカラムを削除して、以下のようにすることも可能です。
public function notifications(): HasMany
{
return $this->hasMany(UserNotification::class)->latest();
}