LoginSignup
2
2

More than 3 years have passed since last update.

Laravel5.5専用 レガシーシステムのDBで、SoftDeleteに対応する唯一の方法

Last updated at Posted at 2019-06-01

Laravel Eloquent SoftDelete

LaravelでEloquentを利用してる皆様、おはこんばんわんこm(__)m

最近、レガシーDBで、OR/Mに対応するときに、論理削除コードで詰まりました。

Laravelでは、論理削除のTraitを利用するときに、SoftDeletesを呼び出す必要が有りますが、
これがまた、削除時にはタイムスタンプが入るようになっています。
DBを初期構築から対応出来るプロジェクトであれば良いのですが、既存のプロジェクトや、削除を 1 0 で対応しているプロジェクトも多いですよね。

論理削除コードを0,1で対応するかどうかなどの、設計思想は置いておいて。。。

とりあえず、SoftDeleteを継承することで対応する事にします。
継承して作成するクラスは、2つだけです。

  • App\Eloquent\ExSoftDeletes
  • App\Eloquent\ExSoftDeletingScope

SoftDeletes Trait

Illuminate\Database\Eloquent\SoftDeletes クラスを継承して、 App\Eloquent\ExSoftDeletes クラスを作成します。
Eroquentでは、Build時のTraitに追加するために、SoftDeleteのbootメソッドにて、 SoftDeletingScope が設定されます。

    public static function bootSoftDeletes()
    {
        static::addGlobalScope(new SoftDeletingScope);
    }

この、 SoftDeletingScope を継承したクラスを作成(次項)するのと、runSoftDelete() メソッドを修正します。(注:他にも対応しなければならいメソッドがあるかも・・・)

以下、全コードです。

<?php

namespace App\Eloquent;

use Illuminate\Database\Eloquent\SoftDeletes;

trait ExSoftDeletes
{
    use SoftDeletes;

    /**
     * Boot the soft deleting trait for a model.
     *
     * @return void
     */
    public static function bootSoftDeletes()
    {
        static::addGlobalScope(new ExSoftDeletingScope);
    }

    /**
     * Perform the actual delete query on this model instance.
     *
     * @return void
     */
    protected function runSoftDelete()
    {
        $query = $this->newModelQuery()->where($this->getKeyName(), $this->getKey());

        $time = 1;

        $columns = [$this->getDeletedAtColumn() => 1];

        $this->{$this->getDeletedAtColumn()} = $time;

        if ($this->timestamps && !is_null($this->getUpdatedAtColumn())) {
            $this->{$this->getUpdatedAtColumn()} = $time;

            $columns[$this->getUpdatedAtColumn()] = 1;
        }

        $query->update($columns);
    }
}

SoftDeletingScope

前出のクラス作成で説明の通り、Queryのbuild時に生成されるクラス SoftDeletingScope を継承してメソッドをオーバーライドします。
検索条件が、whereNull、whereNotNull となっている箇所が、修正のポイントです。
この部分は、プロジェクトのDBに合わせて、修正する必要が有るでしょう。

<?php

namespace App\Eloquent;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletingScope;

class ExSoftDeletingScope extends SoftDeletingScope
{
    /**
     * Apply the scope to a given Eloquent query builder.
     *
     * @param \Illuminate\Database\Eloquent\Builder $builder
     * @param \Illuminate\Database\Eloquent\Model $model
     * @return void
     */
    public function apply(Builder $builder, Model $model)
    {
//        $builder->whereNull($model->getQualifiedDeletedAtColumn());
        $builder->where($model->getQualifiedDeletedAtColumn(), 0);
    }

    /**
     * Add the without-trashed extension to the builder.
     *
     * @param \Illuminate\Database\Eloquent\Builder $builder
     * @return void
     */
    protected function addWithoutTrashed(Builder $builder)
    {
        $builder->macro('withoutTrashed', function (Builder $builder) {
            $model = $builder->getModel();

//            $builder->withoutGlobalScope($this)->whereNull(
//                $model->getQualifiedDeletedAtColumn()
//            );
            $builder->withoutGlobalScope($this)->where(
                $model->getQualifiedDeletedAtColumn(), 0
            );

            return $builder;
        });
    }

    /**
     * Add the only-trashed extension to the builder.
     *
     * @param \Illuminate\Database\Eloquent\Builder $builder
     * @return void
     */
    protected function addOnlyTrashed(Builder $builder)
    {
        $builder->macro('onlyTrashed', function (Builder $builder) {
            $model = $builder->getModel();

//            $builder->withoutGlobalScope($this)->whereNotNull(
//                $model->getQualifiedDeletedAtColumn()
//            );
            $builder->withoutGlobalScope($this)->whereNotNull(
                $model->getQualifiedDeletedAtColumn(), '<>', 0
            );

            return $builder;
        });
    }
}

以上、
あまり真剣にテストしてないので、ご利用は計画的に。。。

なお、Laravel5.6 からはちょっと継承方法が違ってくるらしいので、その時にまた。

2
2
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
2
2