10
11

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 1 year has passed since last update.

【Laravel】論理削除(softDelete)するときにリレーション先のデータも削除する方法

Posted at

概要

Laravelでは、マイグレーションファイルに外部キー制約の設定を記述しておくと、親テーブルのデータを削除したときに子テーブルのデータも同時に削除することができます。

但しこれは、DBから実際にデータを削除する「物理削除」の場合の話です。

DBからレコードを削除するわけではなく削除フラグを立てて削除したとみなす「論理削除」の場合は、マイグレーションファイルへの記述だけではリレーション先のデータを一緒に削除してくれません。

このような場合に、 モデルの boot メソッド(もしくは booted メソッド)を使って初期設定を行えば、あるテーブルのデータを論理削除したときにリレーション先のテーブルのデータも削除することができます。

業務でこの方法を使う機会があったので、 モデル boot メソッドについて勉強したこととあわせて、備忘録を書いておきたいと思います。

論理削除(softDelete)の設定方法

まず事前準備としてソフトデリートの設定をします。

ソフトデリート機能を組み込む手順は以下の2つです。

1. マイグレーションファイルにソフトデリートの設定を記述する
2. EloquentモデルにSoftDeletesトレイトを組み込む

例として users テーブルにソフトデリート機能を設定してみます。

1. マイグレーションファイルにソフトデリートの設定を記述する

Laravelの論理削除ではテーブルの deleted_atカラムに値が入っている場合はデータは削除されたとみなすので、 deleted_atカラムを追加する必要があります。

deleted_atカラムを追加するため、マイグレーションファイルに以下の1行を追記します。

publicfunction up()
{
    Schema::table('user',function (Blueprint $table) {
        $table->softDeletes();    // 追記
    });
}

これでマイグレーションを実行すると、DBのテーブルに deleted_atカラムが作成されていることが確認できます。

2. EloquentモデルにSoftDeletesトレイトを組み込む

User モデルファイルに以下のように追記します。

use Illuminate\Database\Eloquent\SoftDeletes;    // 追記

class User extends Model
{
    use SoftDeletes;    // 追記
}

この記述により、deleteメソッドでモデルを削除した際はソフトデリートが実行されるようになります。

Laravelでソフトデリートを行うための設定は以上です。

モデルのbootedメソッドとは

本題の「ソフトデリートするときにリレーション先のデータも削除する」ための実装にあたり、先に今回使用する boooted メソッドについて少し勉強しておきます。

Laravel のモデルでは、初期起動時に boot メソッドを走らせて初期設定をしています。

booted メソッドはモデルの初期起動後に実行されるメソッドで、モデルに対して行いたい初期設定は booted メソッドに書くよう readouble にも説明があります。

【補足】bootedメソッドとbootメソッドについて

今回実装方法をググっているとbootメソッドを使っている記事が見つかり、自分としても初期起動時のメソッドといえばbootメソッドのイメージがあったので、bootedメソッドとbootメソッドについて少し調べてみました。

readouble の説明では、モデルの初期設定を行う方法としてLaravel6までは boot メソッドが使われていますが、Laravel7以降では booted メソッドが使われていました。

・Laravel8の該当箇所

・Laravel6の該当箇所

試しにモデルファイルに以下のように書き、 booted() のところにマウスをホバーさせてVSCodeのヒントを表示してみます。

// モデルファイルに記述
/**
 * @return void
 */
public static function booted(): void
{
    //
}

// booted() にマウスをホバーさせると、以下の説明が表示される
Illuminate\Database\Eloquent\Model::booted

Perform any actions required after the model boots.

<?php
protected static function booted() { }

bootedメソッドについては、 Perform any actions required after the model boots. と説明されています。

boot() を書いた場合も確認します。

// モデルファイルに記述
/**
 * @return void
 */
public static function boot(): void
{
    //
}

// boot() にマウスをホバーさせると、以下の説明が出る
Illuminate\Database\Eloquent\Model::boot

Bootstrap the model and its traits.

<?php
protected static function boot() { }
@return void

boot メソッドは Bootstrap the model and its traits. と説明がありました。

※実際のLaravelのソースコードだと、以下のファイルに boot メソッドも booted メソッドもありました。 
興味のある方はこちらもご覧ください。

メソッド名の通りですが、 bootedメソッドはモデルの初期起動後に実行されているということですね。

私は業務ではLaravel8を使っており、 boot メソッドでも booted メソッドでも同じように設定を行うことは出来ましたが、現在の readouble の説明に従って bootedメソッドを使っていきたいと思います。

Modelのbootedメソッドにクロージャを書く

前置きが長くなりましたが、実際にモデルの booted メソッドに「データを論理削除したらリレーション先のデータも削除する」設定を記述します。

前提

  • users テーブル(親)と1対多で紐づく posts テーブルがあるとします。
  • users テーブルからレコードを論理削除したら、 リレーション先のposts テーブルからもレコードを論理削除するように設定します。

実装方法

User.phpにリレーションと bootedメソッドを追記します。

class User extends Model
{
    use HasFactory, SoftDeletes;

    /**
     * @return HasMany
     */
    public function posts(): HasMany
    {
        return $this->hasMany(Post::class);
    }

    /**
     * @return void
     */
    public static function booted(): void
    {
        static::deleted(function ($user) {
            $user->posts()->delete();
        });
    }
}

これにより、 users テーブルのデータ削除時に、リレーション先の posts テーブルからも同時に削除してくれます。

posts テーブルに対してもソフトデリートの設定を行っている場合は posts テーブルも論理削除、何も設定していなければ posts テーブルからは物理削除になります。

最後に

論理削除はDBのレコードを削除するわけでは無く、SQLの命令文でいうと UPDATE にあたるので、論理削除の場合はDB的には削除と見なされないということは、よく考えると当たり前でもありますが改めて勉強になりました。

またモデルの boot メソッドや booted メソッドの使い方や、これらが出来ることについても良い学びになりました。

Laravelのライフサイクルの理解を深めれば、もっともっと実装の引き出しが増えるんだろうなと思うので、コツコツ勉強していきたいと思います。

参考記事

10
11
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
10
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?