如何在Laravel中软删除父记录时软删除相关记录?

时间:2015-08-23 05:32:20

标签: php laravel laravel-5 eloquent soft-delete

我有这张发票表,它具有以下结构

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;

}

Invoice表上的softDelete工作正常,但其相关记录(付款)仍然存在。如何使用softDelete删除它们?

4 个答案:

答案 0 :(得分:14)

Eloquent 并不能自动删除相关对象,因此您需要自己编写一些代码。幸运的是,它非常简单。

雄辩的模型在模特的生命周期的不同阶段发布不同的事件,如创建,创建,删除,删除等等。您可以在此处阅读更多相关信息:{{3} }。你需要的是一个在删除事件被触发时运行的监听器 - 这个监听器应该删除所有相关的对象。

您可以在模型的 boot()方法中注册模型侦听器。监听器应该迭代所有要删除的发票的付款,并且应该逐个删除它们。批量删除不会在这里工作,因为它将直接绕过模型事件执行SQL查询。

这样可以解决问题:

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

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

答案 1 :(得分:9)

您可以使用以下两种方法之一。

最简单的方法是覆盖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模型。 另外,我假设您在模型中设置了关系,但是,我不确定您是否允许为一张发票支付多笔款项。无论哪种方式,您都可能需要将示例中的payments()更改为您在发票模型中命名关系的任何内容。

希望这有帮助!

答案 2 :(得分:8)

我知道你很久以前就问了这个问题,但我发现this package非常简单明了。

或者您可以使用this package它也很有用。

请记住根据您的laravel版本安装正确的版本。

您必须通过composer安装它:

 composer require askedio/laravel5-soft-cascade ^version

在第二个包中:

 composer require iatstuti/laravel-cascade-soft-deletes

在config / app.php中注册服务提供商。

您可以在GitHub页面上阅读文档。

如果你删除了一个记录,这个包可以识别它的所有子节点,也可以软删除它们。

如果您的孩子模型中有另一种关系,也要在该模型中使用其特征。它比手动操作容易得多。

第二个包的好处是删除模型的孙子。在某些情况下,我说它是一种更好的方法。

答案 3 :(得分:0)

如果您的数据库关系不仅仅局限于一层,,那么您可以简单地使用Laravel事件在Model boot()方法内处理软删除,如下所示:

<?php
//...

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

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

        }); 
    }

但是,如果您的结构仅比一层更深,那么您将不得不调整这段代码。

例如,您不想删除发票的付款,而是要删除给定用户的全部付款历史记录。

<?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不管其深度有多深都可以跟随兔子的洞。