3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

定期的にモデル削除のPrunable機能到着 [Laravel 8.50]

Posted at

概念

定期的に不要になったレコードをDBから物理的に削除したい場合があるとおもいます。今までこの処理をバッチやコマンドで作る必要がありましたがLaravel 8.50のリリースに含んでいるPrunableMassPrunableのトレイトをモデルクラスに追加することで、この処理が簡単に実装できます。

セットアップ

変更履歴のログや調査のため、ユーザーの名前などの情報が変更されるときにDBのUserLogのテーブルに保存する事を例とします。UserLog情報を6ヶ月間保存する必要があり、定期的に6ヶ月間前のレコードをDBから物理的に削除します。

使い方

モデルの周り

モデルにPrunableのトレイトを追加して、prunableの関数に削除対象のレコードをEloquentのクエリビルダで返す機能を実装します。PrunableMassPrunableを使うとき論理削除のSoftDeletesを利用しているモデルでもクエリに一致した場合、物理的にforceDelete()で削除されますので気を付けてください。


<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Prunable;

class UserLog extends Model
{
    use Prunable;

    /**
     * 削除対処のモデルを取得
     *
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function prunable()
    {
        // 6ヶ月前のレコードを取得する
        return static::where('created_at', '<=', now()->subMonths(6));
    }
}

もしそのモデルと関連する処理(たとえば、古いプロファイルの写真を削除することや、関連するモデル削除など)が必要な場合、モデルが削除する前にpruningという関数で処理が実装できます。


    /**
     * モデルの削除の準備
     *
     * @return void
     */
     protected function pruning()
    {
        // ここでモデルが削除する前に必要な処理を実装します
    }

スケジュール

Prunableを利用しているモデルの削除処理が行われるため、アプリケーションのApp\Console\Kernelクラスでmodel:pruneのArtisanコマンドを登録する必要があります。そのコマンドが実行されるとapp/Modelsディレクトリ内にあるPrunableMassPrunableを利用しているモデルの削除処理が行われます。もしモデルが別のダイレクトリーにあるなら、--modelのオプションを使って、モデルのクラス名を配列として指定できます。下記の例だと毎日の03:00に削除処理が実行されます。

App\Console\Kernel.php
protected function schedule(Schedule $schedule)
{
    // `app/Models`ディレクトリ内の場合
    $schedule->command('model:prune')
        ->daily()
        ->at('03:00');

    // `app/Models`ディレクトリ以外の場合
    $schedule->command('model:prune', [
        '--model' => [UserLog::class],
    ])->daily()
    ->at('03:00');
}

MassPrunable VS Prunable

MassPrunableというのはの複数削除処理が行われ、Prunableと違って削除前にレコードを取得せず、複数レコード削除クエリが実行されます。そのためMassPrunableの方がPrunableより、処理が効率的です。しかし、削除する前にレコードが取得されないため、Eloquentのdeleted・deleting・pruningのイベントは発火しません。それ以外は、Prunableの実装と同じです。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\MassPrunable;

class UserLog extends Model
{
    use MassPrunable;

    /**
     * 削除対処のモデルを取得
     *
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function prunable()
    {
        // 6ヶ月前のレコードを取得する
        return static::where('created_at', '<=', now()->subMonths(6));
    }
    
    /**
     * モデルの削除の準備
    *
     * @return void
     */
    protected function pruning()
    {
        // イベントが発生されないので、この関数の処理が行われない
    }
}

参考

https://github.com/laravel/framework/pull/37696
https://laravel.com/docs/8.x/eloquent#pruning-models
https://laravel.com/api/8.x/Illuminate/Database/Eloquent/Prunable.html
https://laravel.com/api/8.x/Illuminate/Database/Eloquent/MassPrunable.html

3
1
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
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?