1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Laravelのdatabase-notificationsのデフォルトのテーブルを変更する

Posted at

バージョン

  • 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トレイトを利用する必要があります。

app/Models/User.php
class User extends Authenticatable
{
+    use Notifiable;

usersテーブルとは別のテーブルにメールアドレスを保存している場合は、routeNotificationForMailメソッドをUserモデルに作成する必要があります。

app/Models/User.php
class User extends Authenticatable
{
    use Notifiable;

+    public function routeNotificationForMail(): array|string
+    {
+        // usersテーブルではなくrelation先のprofilesテーブルにメールアドレスを保存している場合など
+        return $this->profile->email;
+    }

php artisan make:notification TestNotificationで通知用のクラスを作成します。

app/Notifications/TestNotification.php
<?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メソッドを作成します。

app/Models/User.php
    public function notifications()
    {
        return $this->morphMany(UserNotification::class, 'notifiable')->latest();
    }

デフォルトのnotificationsメソッドはnotifiableトレイトのさらにHasDatabaseNotificationsトレイトにあります。

vendor/laravel/framework/src/Illuminate/Notifications/HasDatabaseNotifications.php
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)

app/Notifications/TestNotification.php
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に書き換えます。

app/Notifications/TestNotification.php
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();
}
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?