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

How to soft delete related records when soft deleting a parent record in Laravel?

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

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

和具有以下结构的付款 table

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 table 完美运行,但其相关记录(付款)仍然 exists.How 我要使用 softDelete 删除它们吗?

您可以选择以下两种方式之一。

最简单的方法是覆盖 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() 更改为您在发票模型中为关系命名的任何内容。

希望对您有所帮助!

Eloquent 不提供自动删除相关对象,因此您需要自己编写一些代码。幸运的是,这很简单。

Eloquent models 在模型生命周期的不同阶段触发不同的事件,例如创建、创建、删除、删除等 - 您可以在这里阅读更多相关信息:http://laravel.com/docs/5.1/eloquent#events。您需要的是一个监听器,它会在触发 deleted 事件时 运行 - 然后这个监听器应该删除所有相关对象。

您可以在模型的 boot() 方法中注册模型侦听器。侦听器应遍历要删除的发票的所有付款,并应将其一一删除。批量删除在这里不起作用,因为它会绕过模型事件直接执行 SQL 查询。

这样做就可以了:

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

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

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

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

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

您必须通过 composer 安装它:

 composer require askedio/laravel5-soft-cascade ^version

在第二个包中:

 composer require iatstuti/laravel-cascade-soft-deletes

在您的 config/app.php.

中注册服务提供商

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

如果您删除一条记录,此包会识别其所有子项并同时软删除它们。

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

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

如果您的数据库关系不超过一层,那么您可以简单地使用 Laravel 事件来处理您在模型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 跟随兔子洞,无论它有多深。