什麼是 Scope
Eloquent 的 Scope 是能將查詢的約束彙整並重複使用的機制。Scope 分為兩種。本地 Scope
定義
本地 Scope 透過在模型的方法上加註#[Scope] attribute 來定義。
#[Scope] attribute 位於 Illuminate\Database\Eloquent\Attributes 命名空間,是 PHP 8.0 以後的原生語法。使用方式
已定義的 Scope 可作為方法呼叫。也能鏈式使用。傳遞參數
可於 Scope 方法的第 2 個引數以後定義額外參數。與 orWhere 的組合
以 orWhere 串接 Scope 時,有時需要邏輯群組。
Global Scope
機制
Global Scope 是實作Illuminate\Database\Eloquent\Scope 介面的類別。此介面僅要求一個 apply 方法。
apply 方法中對查詢建構器加入約束。
建立 Global Scope 類別
以make:scope 指令產生範本。
app/Models/Scopes/ActiveScope.php。
套用至模型
1
以 #[ScopedBy] attribute 註冊(推薦)
Laravel 13 中使用 可以陣列指定多個 Scope。
#[ScopedBy] attribute 最為簡潔。2
於 booted() 方法手動註冊
也可以覆寫
booted 方法並呼叫 addGlobalScope。User::all() 等所有查詢都會自動附加 WHERE is_active = 1。
以匿名 Closure 定義 Global Scope
單純且不至於為其建立獨立檔案的 Scope,可以 closure 定義。Global Scope 的排除
有時希望於特定查詢停用 Scope。框架內部:SoftDeletingScope
觀察 Laravel 標準的SoftDeletes trait 如何運用 Global Scope,即可掌握實作模式。
SoftDeletingScope 實作了 Scope 介面。
來看 withTrashed() 的實作
來看 withTrashed() 的實作
withTrashed() 實際上是呼叫 withoutGlobalScope($this)。也就是排除 SoftDeletingScope 自身,讓已刪除記錄也可取得。onlyTrashed() 同樣是排除自身後再加上 whereNotNull('deleted_at')。實務使用情境
多租戶:以租戶 ID 自動篩選
SaaS 應用程式中,對所有查詢自動套用租戶 ID 篩選相當重要。Post::all() 就會只回傳驗證中使用者的租戶資料。
公開/非公開篩選
於管理後台希望顯示未公開的文章,但於前端僅顯示已公開者的情境。withoutGlobalScope 排除 Scope。
使用 addSelect 而非 select
下一步
Eloquent 自訂 Cast
學習將屬性轉換邏輯實作為自訂 Cast,並活用 Value Object 模式的方法。