让你的ORM条件筛选更加的优雅[合理性的偷懒]
前言
隔了很久再来分享一个小魔法
在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 协议》,转载必须注明作者和本文链接
推荐文章: