隔了很久再來分享一個小魔法
在laravel中,為模型新增篩選條件一般都是使用when方法,如下:
use App\Models\Article;
public function index(Request $request)
{
$articles = Article::with('category:id,name', 'tags:id,name')
->when($request->filled('keyword'), function ($query) use ($request) {
$query->where('title', 'LIKE', "%{$request->query('keyword')}%");
})
->paginate(20, ['id', 'title', 'introduce', 'is_recommend', 'category_id']);
return view('admin.article.index', compact('articles', 'request'));
}
雖然沒使用變數儲存模型控制程式碼,然後再使用if判斷,可是我覺得程式碼是還可以再精【tou】簡【lan】的,下面就來看看如何實現
精妙的使用陣列展開符
在你的基礎模型新增一個公用的scope方法
class Base extends Model
{
/**
* 按需進行條件篩選
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param bool $bool
* @param array $parameters
* @return void
*/
public function scopeWhenWhere(Builder $query, bool $bool, ...$parameters)
{
$bool && $query->where(...$parameters);
}
}
你可能會在想這樣之後呢?這樣之後,就是偷懶的時刻!
/**
* Display a listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\View\View
*/
public function index(Request $request)
{
$articles = Article::with('category:id,name', 'tags:id,name')
->whenWhere($request->filled('keyword'), 'title', 'LIKE', "%{$request->query('keyword')}%")
->whenWhere($request->filled('category_id'), 'category_id', $request->query('category_id'))
->paginate(20, ['id', 'title', 'introduce', 'is_recommend', 'category_id']);
return view('admin.article.index', compact('articles', 'request'));
}
這一行程式碼主要體現在使用陣列展開符,也就是說第一個引數用來做短路判斷,如原來when的第一個引數一樣,接下來的引數按位置傳給where函式,就會達到一模一樣的效果,而且擴充性也是一模一樣的,因為如果你要做複雜的判斷,那麼你也可以傳入閉包【雖然這個時候你使用原來的when也是一樣】
再進化,讓其支援自動執行scope
Article模型內的scopeRecommend方法
/**
* 是否為推薦文章
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param bool $recommend
* @return bool
*/
public function scopeRecommend(Builder $query, bool $recommend = true)
{
$query->where('is_recommend', $recommend);
}
這個需求誕生在我近段時間寫開源的部落格和其附帶的app時遇到的,我不想笨笨的傳入閉包然後在閉包內呼叫scope,如:
$articles = Article::with('category:id,name', 'tags:id,name')
->when($request->filled('is_recommend'), function ($query) use ($request) {
$query->recommend($request->query('is_recommend'));
})
->paginate(20, ['id', 'title', 'introduce', 'is_recommend', 'category_id']);
或者
$articles = Article::with('category:id,name', 'tags:id,name')
->whenWhere($request->filled('is_recommend'), function ($query) use ($request) {
$query->recommend($request->query('is_recommend'));
})
->paginate(20, ['id', 'title', 'introduce', 'is_recommend', 'category_id']);
那麼讓我們對whenWhere這個scope方法進行小小的修改,雖然程式碼就沒有一行那麼精妙,但是如果有需要呼叫scope的同學,可以進行如下修改:
/**
* 按需進行條件篩選
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param bool $bool
* @param array $parameters
* @return void
*/
public function scopeWhenWhere(Builder $query, bool $bool, ...$parameters)
{
if ($bool) {
if (isset($parameters[1]) && $parameters[1] === 'scope') {
$query->{$parameters[0]}(...array_slice($parameters, 2));
} else {
$query->where(...$parameters);
}
}
}
接下來我就只需要這樣使用即可
$articles = Article::with('category:id,name', 'tags:id,name')
->whenWhere($request->filled('is_recommend'), 'recommend', 'scope', $request->query('is_recommend'))
->whenWhere($request->filled('keyword'), 'title', 'LIKE', "%{$request->query('keyword')}%")
->whenWhere($request->filled('category_id'), 'category_id', $request->query('category_id'))
->paginate(20, ['id', 'title', 'introduce', 'is_recommend', 'category_id']);
看完這篇文章,你學會偷懶的正確姿勢了嗎?
最後附帶另外一個小魔法,細心的同學可能還發現了一個地方,那就是我的with的寫法為什麼是冒號加欄位名,請不要誤會,這裡是laravel本身就有的寫法,冒號前面是關聯名稱,冒號後面是需要查詢的欄位,可以很方便的幫你避免使用閉包然後在閉包內使用select方法限定欄位。
預告
下一次發文可能就是開源部落格程式碼的時候了
部落格功能非常非常簡單,前臺使用媒體查詢進行自適應,app端使用flutter進行開發
開發這個僅僅是想提供開發思路給大家,如後臺的封裝,前臺的封裝,寫出更好的程式碼
laravel原始碼內會包含極度正規的程式碼規範和一些程式碼架構封裝【但是並不會使用Repository模式,一些小缺陷會在開源時說明】
如果你想學習php良好的開發姿勢,不妨關注一下
本作品採用《CC 協議》,轉載必須註明作者和本文連結