Skip to main content

什麼是 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 中使用 #[ScopedBy] attribute 最為簡潔。
可以陣列指定多個 Scope。
2

於 booted() 方法手動註冊

也可以覆寫 booted 方法並呼叫 addGlobalScope
加入 Global Scope 後,User::all() 等所有查詢都會自動附加 WHERE is_active = 1

以匿名 Closure 定義 Global Scope

單純且不至於為其建立獨立檔案的 Scope,可以 closure 定義。
要排除以 closure 定義的 Scope,需使用 Scope 名稱(字串)而非類別名稱。

Global Scope 的排除

有時希望於特定查詢停用 Scope。

框架內部:SoftDeletingScope

觀察 Laravel 標準的 SoftDeletes trait 如何運用 Global Scope,即可掌握實作模式。 SoftDeletingScope 實作了 Scope 介面。
withTrashed() 實際上是呼叫 withoutGlobalScope($this)。也就是排除 SoftDeletingScope 自身,讓已刪除記錄也可取得。
onlyTrashed() 同樣是排除自身後再加上 whereNotNull('deleted_at')
Scope 介面並未定義 extend 方法,但 Eloquent 的 Builder 若發現 Scope 具備 extend 方法就會自動呼叫。可用於新增自訂 macro。

實務使用情境

多租戶:以租戶 ID 自動篩選

SaaS 應用程式中,對所有查詢自動套用租戶 ID 篩選相當重要。
如此只要呼叫 Post::all() 就會只回傳驗證中使用者的租戶資料。

公開/非公開篩選

於管理後台希望顯示未公開的文章,但於前端僅顯示已公開者的情境。
於管理後台以 withoutGlobalScope 排除 Scope。

使用 addSelect 而非 select

於 Global Scope 中加入欄位時,請使用 addSelect 而非 select。使用 select 會覆寫呼叫端查詢中 select 的欄位。

下一步

Eloquent 自訂 Cast

學習將屬性轉換邏輯實作為自訂 Cast,並活用 Value Object 模式的方法。
最後修改於 2026年8月2日