web-dev-qa-db-ja.com

Laravelで親レコードをソフト削除するときに関連レコードをソフト削除するにはどうすればよいですか?

次の構造の請求書テーブルがあります

id | name | amount | deleted_at
2    iMac   1500   | NULL

および次の構造の支払いテーブル

id | invoice_id | amount | deleted_at
2    2            1000   | NULL

請求書モデル

class Invoice extends Model {

    use SoftDeletes;

}

請求書を削除するコードは次のとおりです

public function cance(Request $request,$id)
{
    $record = Invoice::findOrFail($id);
    $record->delete();
    return response()->json([
        'success' => 'OK',
    ]);
}

支払いモデル

class Payment extends Model {

    use SoftDeletes;

}

請求書テーブルのsoftDeleteは完全に機能しますが、関連するレコード(支払い)はまだ存在します。softDeleteを使用してそれらを削除するにはどうすればよいですか?

14
user3407278

Eloquentは関連オブジェクトの自動削除を提供しないため、自分でコードを作成する必要があります。幸いなことに、それは非常に簡単です。

Eloquentモデルは、作成、作成、削除、削除など、モデルのライフサイクルのさまざまな段階でさまざまなイベントを発生させます。詳細については、こちらをご覧ください。 http://laravel.com/docs/5.1/eloquent#events 。必要なのは、deletedイベントが発生したときに実行されるリスナーです。このリスナーは、関連するすべてのオブジェクトを削除する必要があります。

モデルのboot()メソッドにモデルリスナーを登録できます。リスナーは、削除される請求書のすべての支払いを繰り返し処理し、それらを1つずつ削除する必要があります。一括削除は、モデルイベントを直接バイパスしてSQLクエリを実行するため、ここでは機能しません。

これでうまくいきます:

class MyModel extends Model {
  protected static function boot() {
    parent::boot();

    static::deleted(function ($invoice) {
      $invoice->payments()->delete();
    });
  }
}
15
jedrzej.kurylo

これで2つの方法のいずれかに行くことができます。

最も簡単な方法は、Eloquents delete()メソッドをオーバーライドし、関連するモデルも含めることです。例:

_public function delete()
{
    $this->payments()->delete();
    return parent::delete();
} 
_

上記の方法は見つけるだけで機能するはずですが、少し汚いようで、コミュニティ内で推奨される方法ではないと思います。

よりクリーンな方法(IMO)は、Eloquentsイベントを利用することです。

_public static function boot()
{
    parent::boot();

    static::deleting(function($invoice) { 
         $invoice->payments()->delete();

    });
}
_

上記のメソッドのいずれか(両方ではない)がInvoiceモデルに適用されます。また、モデルに関係が設定されていることを前提としていますが、1つの請求書に対して複数の支払いを許可するかどうかはわかりません。いずれにせよ、例のpayments()を、請求書モデルで関係に名前を付けたものに変更する必要があるかもしれません。

お役に立てれば!

9
Rwd

ずっと前にこの質問をしたことは知っていますが、 このパッケージ は非常に単純でわかりやすいことがわかりました。

または、 このパッケージ を使用することもできます。これも便利です。

laravelバージョンに応じて正しいバージョンをインストールすることを忘れないでください

Composerを介してインストールする必要があります。

 composer require askedio/laravel5-soft-cascade ^version

2番目のパッケージ:

 composer require iatstuti/laravel-cascade-soft-deletes

Config /app.phpにサービスプロバイダーを登録します。

gitHubページでドキュメントを読むことができます。

レコードを削除すると、このパッケージはそのすべての子を認識し、それらもソフト削除します。

チャイルドモデルに別の関係がある場合は、そのモデルでもその特性を使用します。手動で行うよりもはるかに簡単です。

2番目のパッケージには、モデルの孫を削除するという利点があります。場合によっては、より良いアプローチだと思います。

6
Salar Bahador

データベースの関係が1つのレイヤーだけにとどまらない場合Laravelイベントを使用して、モデル内のソフト削除を処理できますboot()メソッドは次のとおりです。

<?php
//...

    protected static boot() {
        parent::boot();

        static::deleting(function($invoice) { 
             $invoice->payments()->delete();

        }); 
    }

ただし、構造が1つのレイヤーだけよりも深くなる場合、そのコードを微調整する必要があります。

たとえば、請求書の支払いを削除するのではなく、特定のユーザーの支払い履歴全体を削除したいとします。

<?php

// ...

class Invoice extends Model
{
    // ...

    /**
     * Holds the methods names of Eloquent Relations
     * to fall on delete cascade or on restoring
     * 
     * @var array
     */
    protected static $relations_to_cascade = ['payments']; 

    protected static boot()
    {
        parent::boot();

        static::deleting(function($resource) {
            foreach (static::$relations_to_cascade as $relation) {
                foreach ($resource->{$relation}()->get() as $item) {
                    $item->delete();
                }
            }
        });

        static::restoring(function($resource) {
            foreach (static::$relations_to_cascade as $relation) {
                foreach ($resource->{$relation}()->get() as $item) {
                    $item->withTrashed()->restore();
                }
            }
        });
    }

    public function payments()
    {
        return $this->hasMany(Payment::class);
    }
}

<?php

// ...

class User extends Model
{
    // ...

    /**
     * Holds the methods names of Eloquent Relations 
     * to fall on delete cascade or on restoring
     * 
     * @var array
     */
    protected static $relations_to_cascade = ['invoices']; 

    protected static boot()
    {
        parent::boot();

        static::deleting(function($resource) {
            foreach (static::$relations_to_cascade as $relation) {
                foreach ($resource->{$relation}()->get() as $item) {
                    $item->delete();
                }
            }
        });

        static::restoring(function($resource) {
            foreach (static::$relations_to_cascade as $relation) {
                foreach ($resource->{$relation}()->get() as $item) {
                    $item->withTrashed()->restore();
                }
            }
        });
    }

    public function invoices()
    {
        return $this->hasMany(Invoice::class);
    }
}

このパラダイムは、Laravelがどんなに深くても、ウサギの穴をたどることを保証します。

0
Waiyl Karim