引言
原則上程式碼寫一次,處處是引用,不需要大量的冗餘程式碼,這是一種趨勢,也是提高程式碼健壯性的努力方向。
laravel模型為我們提供了一層資料庫操作層,將資料互動獨立出來。
但是久而久之,隨著專案的需求不斷擴大,最常用的查詢操作,同樣會有大量的冗餘程式碼。
本文就來講講,連模型的自我瘦身,縮減模型的程式碼。
全域性作用域
假設有些資料庫查詢操作,無論是在控制器內,或者在模板檔案內,或者命令列方法內,都有重複的使用需求,要是在模型內有一個公用的方法,預設就加上這些篩選條件,就可以顯著減少程式碼量了。
比如有一個查詢條件:
$publishedEvents = Event::where('published', '=', 1)->get();
上述程式碼最後生成的SQL語句如下:
SELECT * FROM events WHERE `published` = 1;
如果條件 published = 1 在預設的情況下需要開啟,我們可以使用laravel模型的 全域性作用域 方式為所有查詢追加上這個條件。
在模型檔案 Event 內頭部引入下述類:
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
在模型類內部,手動實現 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領域原創作者
本作品採用《CC 協議》,轉載必須註明作者和本文連結