sofa/eloquent-cascade

Laravel Eloquent ORM 的级联删除。

v6.1.1 2021-04-06 02:40 UTC

This package is auto-updated.

Last update: 2024-09-06 10:30:26 UTC


README

Downloads stable

Eloquent ORM (Laravel 5.0+) 提供级联(软/硬)删除功能。

为什么使用这个包? 已经有几个包提供了 Eloquent 的级联删除功能,但没有一个与查询构建器兼容。在这里,您将获得对 $model->delete()$query->delete() 的支持,以及 $model->forceDelete()

安装

包与 Laravel (Illuminate) 版本兼容,以便您轻松选择合适的版本

Laravel / Illuminate 5.2+

composer require sofa/eloquent-cascade:"~5.2"

Laravel / Illuminate 5.0/5.1

composer require sofa/eloquent-cascade:"~5.1"

用法

在您的模型中使用提供的 CascadeDeletes 特性,并定义要级联删除的关系。相关模型将自动且适当地被删除,即 硬删除软删除,具体取决于相关模型设置和使用的删除方法。

tldr;

  1. $model->delete() & $query->delete() 无软删除
  2. 使用软删除时确保特性顺序: use SoftDeletes, CascadeDeletes
  3. $model->delete() & $query->delete() 带软删除
  4. $model->forceDelete() 但是 $query->forceDelete() 将不会工作

简单

<?php

namespace App;

use Sofa\EloquentCascade\CascadeDeletes;

class Product extends \Illuminate\Database\Eloquent\Model
{
    use CascadeDeletes;

    protected $deletesWith = ['types', 'photos'];
  • 在模型上调用 delete()

    root@578687bd11c8:/var/www/html# php artisan tinker
    Psy Shell v0.7.2 (PHP 7.0.3 — cli) by Justin Hileman
    >>> DB::enableQueryLog()            
    => null
    >>> App\Product::find(200)->delete()
    => true
    >>> DB::getQueryLog()
    => [
         [
           "query" => "select * from `products` where `products`.`id` = ? limit 1",
           "bindings" => [200],
         ],
         [
           "query" => "delete from `products` where `id` = ?",
           "bindings" => [200],
         ],
         [
           "query" => "delete from `product_types` where `product_types`.`product_id` = ? and `product_types`.`product_id` is not null",
           "bindings" => [200],
         ],
         [
           "query" => "delete from `photos` where `photos`.`product_id` = ? and `photos`.`product_id` is not null",
           "bindings" => [200],
         ],
       ]
  • 在 Eloquent 查询 Builder 上调用 delete()

    >>> App\Product::whereIn('id', [202, 203])->delete()
    => 2
    >>> DB::getQueryLog()
    => [
         [
           "query" => "select * from `products` where `id` in (?, ?)",
           "bindings" => [202, 203],
         ],
         [
           "query" => "delete from `product_types` where `product_types`.`product_id` in (?, ?)",
           "bindings" => [202, 203],
         ],
         [
           "query" => "update `photos` set `deleted_at` = ?, `updated_at` = ? where `photos`.`product_id` in (?, ?) and `photos`.`deleted_at` is null",
           "bindings" => [
             "2016-05-31 09:44:41",
             "2016-05-31 09:44:41",
             202,
             203,
           ],
         ],
         [
           "query" => "delete from `products` where `id` in (?, ?)",
           "bindings" => [202, 203],
         ],
       ]

SoftDeletes 一起使用

注意 特性的使用顺序很重要,因此请确保您在 CascadeDeletes 之前使用 SoftDeletes

<?php

namespace App;

use Sofa\EloquentCascade\CascadeDeletes;
use Illuminate\Database\Eloquent\SoftDeletes;

class Product extends \Illuminate\Database\Eloquent\Model
{
    use SoftDeletes, CascadeDeletes;

    // related Photo model uses SoftDeletes as well, but Type does not
    protected $deletesWith = ['types', 'photos'];
  • 带软删除的级联 - 每个使用 SoftDeletes 的模型都会软删除,其他则硬删除

    >>> App\Product::whereIn('id', [300, 301])->delete()
    => 2
    >>> DB::getQueryLog()
    => [
         [
           "query" => "select * from `products` where `id` in (?, ?) and `products`.`deleted_at` is null",
           "bindings" => [300, 301],
         ],
         [
           "query" => "delete from `product_types` where `product_types`.`product_id` in (?, ?)",
           "bindings" => [300, 301],
         ],
         [
           "query" => "update `photos` set `deleted_at` = ?, `updated_at` = ? where `photos`.`product_id` in (?, ?) and `photos`.`deleted_at` is null",
           "bindings" => [
             "2016-05-31 09:52:30",
             "2016-05-31 09:52:30",
             300,
             301,
           ],
         ],
         [
           "query" => "update `products` set `deleted_at` = ?, `updated_at` = ? where `id` in (?, ?) and `products`.`deleted_at` is null",
           "bindings" => [
             "2016-05-31 09:52:30",
             "2016-05-31 09:52:30",
             300,
             301,
           ],
         ],
       ]
  • 在模型上调用 forceDelete() 会对所有关系进行硬删除(注意 由于 Laravel 核心中 forceDelete 的当前实现,它不会在 Builder 上工作)

    >>> App\Product::find(302)->forceDelete()
    => true
    >>> DB::getQueryLog()
    => [
         [
           "query" => "select * from `products` where `products`.`id` = ? and `products`.`deleted_at` is null limit 1",
           "bindings" => [302],
         ],
         [
           "query" => "delete from `products` where `id` = ?",
           "bindings" => [302],
         ],
         [
           "query" => "delete from `product_types` where `product_types`.`product_id` = ? and `product_types`.`product_id` is not null",
           "bindings" => [302],
         ],
         [
           "query" => "delete from `photos` where `photos`.`product_id` = ? and `photos`.`product_id` is not null",
           "bindings" => [302],
         ],
       ]

待办事项

  • 级联恢复软删除的模型
  • 分离 m-m 关系 / 删除相关
  • 添加 SET NULL 和 RESTRICT 选项 (?)

贡献

欢迎所有贡献,PR 必须遵守 PSR-2 规范。

变更日志

v6 <- v5.x

  • 现在恢复将只对与父模型一起删除的子模型进行级联,而不是之前。也就是说,如果某些子模型在父模型删除之前已经软删除,那么在父模型恢复时,这些子模型不会被恢复。这是预期的行为。
  • 这要求当在查询构建器上调用恢复而不是单个模型($query->restore()$model->restore())时,它将运行 N 个查询,每个恢复的模型一个。