How to soft delete related records when soft delet

2019-04-19 07:32发布

问题:

I have this invoices table that which has the following structure

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

and a payments table with the following structure

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

Invoice Model

class Invoice extends Model {

    use SoftDeletes;

}

here's the code to delete the invoice

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

Payments model

class Payment extends Model {

    use SoftDeletes;

}

The softDelete on Invoice table works perfectly but its related records (payments) still exists.How do I delete them using softDelete?

回答1:

Eloquent doesn't provide automated deletion of related objects, therefore you'll need to write some code yourself. Luckily, it's pretty simple.

Eloquent models fire different events in different stages of model's life-cycle like creating, created, deleting, deleted etc. - you can read more about it here: http://laravel.com/docs/5.1/eloquent#events. What you need is a listener that will run when deleted event is fired - this listener should then delete all related objects.

You can register model listeners in your model's boot() method. The listener should iterate through all payments for the invoice being deleted and should delete them one by one. Bulk delete won't work here as it would execute SQL query directly bypassing model events.

This will do the trick:

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

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


回答2:

You can go one of 2 ways with this.

The simplest way would be to override Eloquents delete() method and include the related models as well e.g.:

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

The above method should work just find but it seems a little bit dirty and I'd say it's not the preferred method within the community.

The cleaner way (IMO) would be to tap into Eloquents events e.g.:

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

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

    });
}

Either (but not both) of the above methods would go in your Invoice model. Also, I'm assuming that you have your relationships set up in your model, however, I'm not sure if you allow multiple payments for one invoice. Either way you might need to change the payments() in the examples to whatever you've named the relationship in your invoice model.

Hope this helps!



回答3:

I know you asked this question a long time ago but I found this package to be very simple and straightforward.

Or you can use this package it's useful too.

Remember to install the right version depending on your laravel version.

You must install it via composer:

 composer require askedio/laravel5-soft-cascade ^version

In second package:

 composer require iatstuti/laravel-cascade-soft-deletes

Register the service provider in your config/app.php.

you can read the docs on the GitHub page.

If you delete a record this package recognizes all of its children and soft-delete them as well.

If you have another relationship in your child model use its trait in that model as well. its so much easier than doing it manually.

The second package has the benefit of deleting grandchildren of the model. in some cases, I say its a better approach.