几乎任何一个系统,都会涉及到搜索,并且可以搜索的项也很可能多。特别是做一些 OA 、ERP 、 CMS 、CRM 等后台系统的时候,各种报表,各种维度的搜索,非常常见。
一个系统会有非常多的列表。每个列表,可能要搜索的字段会有十来个或者更多。搜索的种类有 like 、全等、包含、区间、具体的业务条件等等。
没有经验的程序员可能会在 controller 里面写非常多的判断,非常多的 query 查询。就算是一些有经验的程序员,也很头疼该如何设置写这些逻辑,如何写的优雅。
我做了很多的后台系统,深知其中的痛楚,所以有了这个包,来一刀命中要害,让复杂的搜索简单起来,便于维护,容易理解,同时也变得优雅起来。
public function wheres()
{
return [
'status',
// 如果传参 status=1 的话 where status = '1';
// 如果 status 前端没有传值,那么不会构造
'created_at.gt' => $this->fireInput('year', function ($year) {
return carbon($year.'-01-01 00:00:00');
}),
// 如果 year 不传值,什么都不会构造。
//如果传值 year=2018,那么就会执行闭包方法, 根据闭包结果构造 where year>'2018-01-01 00:00:00'
'name.like' => $this->appendInput('name', '%'),
// 如果 name 不传值,什么都不会构造。
// 如果传值 name=张 ,那么就会构造 where name like '张%'
'id.in' => $this->getInputArgs('ids', []),
// 如果 ids 不传值,什么都不会构造,因为默认值为 [] ,构造时会被忽略。
// 如果传值 ids=[1,3,4] ,那么就会构造 where id in (1,3,4)
'deleted_at.is_not' => true,
// 如果判断某个字段是否为 null ,使用 is_not 或者 is ,但是注意对应的值不能为 null ,因为值为 null 时,会被自动跳过
'age' => [
'gt' => 12,
'lt' => 16,
],
// where age > 12 and age < 16
'height' => [
'gt' => '180',
'lt' => '160',
'mix' => 'or',
],
// (age > 180 or age < 160)
DB::raw('3=4'),
// where 3=4
function (Builder $q) {
$q->where('id', 4);
},
// where id=4
new ModelScope('popular'),
// 会调用的对应的模型 scopePopular 方法
new ModelScope('older', 60),
// 等同于
function (Builder $q) {
$q->older(60);
},
'id' => When::make(true)->success('34'),
// where id = 34
'url' => When::make(false)->success('http://www.baidu.com')->fail('http://www.google.com'),
// where url='http://www.google.com'
];
}
composer require "matrix-lab/laravel-advanced-search"
如果传递的参数内容并不能满足需要,还需要进行一些简单的加工,可以这样做:
return [
'name.like' => $this->fireInput('name', function ($value) {
return $value.'%';
})
];
这样就能通过 ?name=张
来获取所有姓张的员工。
fireInput
方法
第一个参数:前端的传参 key
第二个参数:处理这个传参的内容
fireInput
行为
如果不能够获取前端传参,那么直接返回 null ,也就是后续处理中会过滤都这条 where 规则
如果能够获取值,那么将获取值传递到闭包,可以自由的进行处理
如果仅仅是想在获取的参数值后面添加数据,可以这样来:
return [
'name.like' => $this->appendInput('name', '%')
];
但是你可能会问,为什么不获取数据之后直接添加 %
?
return [
'name.like' => $this->input('name').'%'
];
第二种写法是错误的,因为可能返回结果是这样的,当前端没有传参时,结果如下:
return [
'name.like' => '%'
];
这样会按照值为 %
进行搜索。
当这个人是被禁用户的时候,我们会额外添加一个搜索条件,不让该用户搜索到任何内容
return [
'id' => $this->when(user()->locked_at, 0),
];
这里会根据 user()->locked_at
值进行判断,得到的结果如下
// user()->locked_at 值存在
return [
'id' => 0,
];
// user()->locked_at 值不存在
return [
'id' => null,
];
根据之前约定的,如果 键值
为空值(包括空字符串,但不包括 0 ),这个条件就不会生效
when
还有以下用法,满足你的各种需求:
'your_field_in_mysql' => $this->when($bool, function() {
# 这里你可以写你的逻辑,最后返回值即可
return $this->your_field_in_request/2;
# 也可以调用一些方法
# 如果是局部方法,能用 private 就不要用 protected 更不要用 public 定义
return $this->yourMethodToTransform($value);
# 同理,返回 null 的时候,这行条件不生效
return null;
}),
原生的 DB::raw 我们也要支持,这个不需要别的,只需要你的语句,只要你会 sql
,就可以写
return [
DB::raw('1=0'),
];
如果你的查询特别复杂,以上各种形式都满足不了,那么你可以祭出终极大招了
use Illuminate\Database\Eloquent\Builder;
return [
function (Builder $q) {
$q->whereHas('role');
},
];
闭包只有一个传参,$q
为 Illuminate\Database\Eloquent\Builder
。看到了这个类,你应该知道如何去使用了吧!
这个就是原生的 laravel
查询对象,把所有你需要的查询放里面吧!剩下不多说,自由发挥去吧!
查询的时候,经常会有一些逻辑,他们之间可能是 and 或者是 or
return [
'created_at' => [
'gt' => '2017-09-01',
'lt' => '2017-09-30'
],
];
默认 created_at
的 大于小于
操作是 and
关联,
如果需要 or
操作,可以这样写
return [
'id' => [
'in' => [23, 24, 30],
'lt' => 25,
'mix' => 'or'
],
];
return [
new ModelScope('listByUser'),
];
上面的代码会在执行的时候,会调用模型的 scopeListByUser 方法。
如果需要传参:
return [
new ModelScope('older', 60),
];
上面的代码等同于
function (Builder $q) {
$q->older(60);
},
return [
'id' => When::make(true)->success('34'),
'url' => When::make(false)->success('http://www.baidu.com')->fail('http://www.google.com'),
];
执行的结果为
where id = 34
where url='http://www.google.com'
有什么新的想法和建议,欢迎提交 issue 或者 Pull Requests。
MIT