[擴充套件包] Laravel-softdeletes 讓資料表支援唯一索引,用於替代內建的軟刪除功能

Jiangqh發表於2021-01-17

Laravel內建的軟刪除功能是一個非常方便的功能,但是這個功能有個很大的缺點:使用了軟刪功能會導致不能給欄位增加唯一索引(unique)。因為一旦給資料表增加了唯一索引,那麼被軟刪的資料很容易就與未刪除的正常資料產生衝突,在絕大多數業務中這種情況都是不允許發生的!比如使用者表的手機號,郵箱等。

所以如果你的資料表中的欄位有需要保持唯一性的需求,一旦使用Laravel內建的軟軟刪除功能,那就需要靠程式邏輯去保證欄位的唯一性,這會給日常開發帶來很多不必要的麻煩,增加不必要的開銷!比如我司的一部分業務使用了軟刪除功能,所以欄位不能增加唯一索引,就導致需要在程式邏輯中對資料加鎖處理,大大降低了程式的的效能。

Laravel內建的軟刪除功能的另外一個不足就是被軟刪除的資料一般都是很少用到的,所以跟正常資料放在同一張資料表對效能也會有所影響。

所以基於以上原因,我寫了Laravel softdeletes,用於替代Laravel內建的軟刪除(softDelets)功能,可以把軟刪資料儲存到獨立的資料表中,從而不影響原始表欄位增加唯一索引,且可以起到提升效能的作用,用法與內建功能幾乎100%一致。

github.com/jqhph/laravel-softdelet... (如果喜歡這個專案不妨點個 star,謝謝支援~)

環境

  • PHP >= 7
  • laravel >= 5.5

安裝

composer require dcat/laravel-softdeletes

使用

首先需要建立兩張欄位一模一樣的資料表,並且兩張表都需要新增deleted_at欄位

// 文章表
Schema::create('posts', function (Blueprint $table) {
    $table->bigIncrements('id');
    $table->string('title')->nullable();
    $table->string('body')->nullable();

    // 兩張表都需要刪除時間欄位
    $table->timestamp('deleted_at')->nullable();

    $table->timestamps();
});

// 文章軟刪除表
Schema::create('posts_trash', function (Blueprint $table) {
    $table->bigIncrements('id');
    $table->string('title')->nullable();
    $table->string('body')->nullable();

    // 兩張表都需要刪除時間欄位
    $table->timestamp('deleted_at')->nullable();

    $table->timestamps();
});

模型定義如下,預設的軟刪除表表名為:{原始表}_trash,如上面的posts表的預設軟刪除表表名是posts_trash

<?php

namespace App\Models;

use Dcat\Laravel\Database\SoftDeletes;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use SoftDeletes;

    /**
     * 自定義軟刪除表表名,預設為 {$table}_trash 
     * 
     * @var string 
     */
    protected $trashedTable = 'posts_trash';

    /**
     * 自定義軟刪除表表名,如有需要可以重寫此方法
     * 
     * @return mixed
     */
    public function getTrashedTable()
    {
        return $this->trashedTable;
    }
}

除了withTrashed只能用於查詢資料之外,其他方法的使用與Laravel內建的軟刪除功能完全一致,下面是簡單的用法示例

需要注意withTrashed只能用於查詢資料,不能用於updatedelete!!!

查詢正常表資料

$posts = Post::where(...)->get();

僅查詢軟刪除表資料 (onlyTrashed)

$trashedPosts = Post::onlyTrashed()->where(...)->get();

同時查詢正常和軟刪資料 (withTrashed),需要注意withTrashed只能用於查詢資料,不能用於updatedelete!!!

Post::withTrashed()
    ->where(...)
    ->offset(5)
    ->limit(5)
    ->get();

// 可以使用子查詢以及whereHas等
Post::withTrashed()
    ->whereHas('...', function ($q) {
        $q->where(...);
    })
    ->offset(5)
    ->limit(5)
    ->get();

// 分頁
Post::withTrashed()
    ->whereHas('...', function ($q) {
     $q->where(...);
    })
    ->paginate(10);

軟刪除/硬刪除/還原

$post = Post::first();

// 軟刪除
$post->delete();

// 還原
$post->restore();

// 硬刪
$post->forceDelete();

// 批次軟刪
Post::where(...)->delete();

// 批次硬刪
Post::onlyTrashed()->where(...)->delete();
本作品採用《CC 協議》,轉載必須註明作者和本文連結
Jiangqh

相關文章