引言
原則上代碼寫一次,處處是引用,不需要大量的冗餘代碼,這是一種趨勢,也是提高代碼健壯性的努力方向。 laravel模型為我們提供了一層數據庫操作層,將數據交互獨立出來。
但是久而久之,隨著項目的需求不斷擴大,最常用的查詢操作,同樣會有大量的冗餘代碼。
本文就來講講,連模型的自我瘦身,縮減模型的代碼。
全局作用域
假設有些數據庫查詢操作,無論是在控制器內,或者在模板文件內,或者命令行方法內,都有重複的使用需求,要是在模型內有一個公用的方法,默認就加上這些篩選條件,就可以顯著減少代碼量了。
比如有一個查詢條件:
$publishedEvents = Event::where('published', '=', 1)->get();
上述代碼最後生成的SQL語句如下:
SELECT * FROM events WHERE published
= 1;
如果條件 published = 1 在默認的情況下需要開啟,我們可以使用laravel模型的 全局作用域 方式為所有查詢追加上這個條件。
在模型文件 Event 內頭部引入下述類:
use IlluminateDatabaseEloquentModel;
use IlluminateDatabaseEloquentBuilder;
在模型類內部,手動實現 boot 方法:
protected static function boot()
{
parent::boot();
static::addGlobalScope('published', function (Builder $builder) {
$builder->where('published', '=', 1);
});
}
這樣SQL語句 where published = 1 就會追加到所有的模型查詢方法內,只要是創建生成了 QueryBuilder 對象的,都會附加上此約束語句。
那有些讀者可能要問了:“如果我不想要這個約束語句,豈不是連模型也永不了了?”
那哪兒能呢!不過就是QueryBuilder的一個屬性數組的一個元素而已,手動移除就行了,這樣特例問題就解決了。
$events = Event::withoutGlobalScopes()->get();
看到了吧,追加上很簡單,移除更簡單。
本地作用域
接上一節的 withoutGlobalScope 要每次手動屏蔽的方式不同,有時候使用有侷限的作用域更能解決問題。所以,本地作用域 應運而生,專門用於某個模型文件的方法,手動調用的時候就起作用,不調用就不會主動追加。
而聲明一個本地作用域,只要遵循laravel的語法規定即可,如下示例:
public function scopePublished($query)
{
return $query->where('published', 1);
}
只需要聲明一個以 scope 為首的小駝峰命名的函數方法即可,並返回一個 QueryBuilder 對象實例。調用的時候要手動追加上:
$events = Event::published()->get();
其中 published()方法就是映射到 scopePublished 方法。
上面的演示代碼,沒有接收用戶輸入,下面演示一下帶參的傳遞方式。比如有這樣一個查詢需求:
$events = Event::where('zip', $zipCode)->get();
使用本地作用域實現出來:
public function scopeZip($query, $zip)
{
return $query->where('zip', $zip);
}
按照位置傳入即可。使用的使用,直接傳入:
$zip = '43016';
$events = Event::zip($zip)->get();
這樣就完成了本地作用域的使用,是不是很直觀。
既然本地作用域返回的是 QueryBuilder 實例,那麼自然就可以鏈式調用本地作用域的方法,和 QueryBuilder 的方法。我們再聲明一個本地作用域方法:
public function scopeAttendees($query, $maximum)
{
return $query->where('max_attendees', $maximum);
}
現在把上述兩個方法串聯使用:
$events = Event::zip(43016)->attendees(2)->get();
生成的SQL語句也符合預期:
SELECT * FROM events WHERE zip = '43016' and max_attendees = '2';
寫在最後
本期我們又舊事重提,把laravel模型的作用域設計方法拿出來溫習了一下。講述了兩個方法:
全局作用域:全局起作用,需要手動移除;
本地作用域:只有手動調用起作用,可鏈式使用;
這樣的設計模式可以很大程度上節約查詢代碼,但是對於維護,需要同等熟悉的開發者彼此遵循開發規範,寫出可維護的代碼。
Happy coding 🙂
我是@程序員小助手,專注編程知識,圈子動態的IT領域原創作者