简化我们做后台时对列表的筛选代码
在写后台接口的时候,我们会使用到大量的筛选,比如状态筛选、时间筛选、关键筛选等等等。
起初在控制器中我是习惯:
..
..
public function index(Request $request)
{
$user = User::query();
if($status = $request->input('status'))
{
}
if($isAdmin = $request->input('xxx'))
{
}
....
return $user->paginate(xxx);
}
后面随着需要筛选的字段越来越多,又或者我的后台比较简单,基本都是只有关键字筛选,这样我们就是一直在写同样的代码。
下面我们利用 局部作用域 来改善一下。
首先我们定义一个 trait
:
<?php
namespace xxx;
use App\Filters\Filter;
use Illuminate\Database\Eloquent\Builder;
/**
* Trait FilterScopeTrait
*
* @package App\Models\Traits
*/
trait FilterScopeTrait
{
/**
* @param \Illuminate\Database\Eloquent\Builder $builder
* @param \App\Filters\Filter $filter
*
* @return \Illuminate\Database\Eloquent\Builder
*
* @author : stringer <10******56@qq.com>
* @datetime : 2020/11/24 10:15
*/
public function scopeFilter(Builder $builder, Filter $filter)
{
return $filter->filter($builder);
}
}
然后我们将这个 trait
在模型中引入。我这边图方便就直接定义一个基类 Model
:
<?php
namespace App\Models;
use xxx\FilterScopeTrait;
use Illuminate\Database\Eloquent\Model as BaseModel;
/**
* @method static \Illuminate\Database\Eloquent\Builder|static filter(\App\Filters\Filter $filter)
*
* @package App\Models
*/
class Model extends BaseModel
{
use FilterScopeTrait;
}
让我们的 User
继承新的 Model
<?php
namespace App\Models;
/**
* @method static Builder|User filter(\App\Filters\Filter $filter)
*/
class User extends Model
{
...
...
...
}
定义 Filter
类
<?php
namespace App\Filters;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
/**
* Class Filter
*
* @package App\Filters
*/
abstract class Filter
{
/**
* @var \Illuminate\Database\Eloquent\Builder
*/
protected $builder;
/**
* @var \Illuminate\Http\Request
*/
protected $request;
/**
* @var array
*/
protected $filters = [];
/**
* Filter constructor.
*
* @param \Illuminate\Http\Request $request
*/
public function __construct(Request $request)
{
$this->request = $request;
}
/**
* 筛选项
*
* @return array
*
* @author : stringer <10******56@qq.com>
* @datetime : 2020/11/24 9:53
*/
protected function getFilters(): array
{
return $this->request->only($this->filters);
}
/**
* @param \Illuminate\Database\Eloquent\Builder $builder
*
* @return \Illuminate\Database\Eloquent\Builder
*
* @author : stringer <10******56@qq.com>
* @datetime : 2020/11/24 10:02
*/
public function filter(Builder $builder)
{
$this->builder = $builder;
foreach ($this->getFilters() as $filter => $value) {
if (method_exists($this, $filter)) {
$this->$filter($value);
}
}
return $this->builder;
}
/**
* 转布尔值
*
* @param string $val 要转的值
*
* @return bool
*
* @author : stringer <10******56@qq.com>
* @datetime : 2020/11/25 16:04
*/
protected function str2Bool(string $val)
{
return filter_var($val, FILTER_VALIDATE_BOOLEAN);
}
}
接下来就是定义 UserFilter
来专门处理 User
可能的筛选
<?php
namespace App\Filters;
/**
* Class AdminOperatingLogFilter
*
* @package App\Filters
*/
class UserFilter extends Filter
{
/**
* @var string[]
*/
protected $filters = [
'keyword', 'regisiterTime', 'type', 'isActive',
];
/**
* 关键字筛选
*
* @param string $keyword
*
* @return \Illuminate\Database\Eloquent\Builder
*
* @author : stringer <10******56@qq.com>
* @datetime : 2020/11/24 10:35
*/
public function keyword(string $keyword)
{
return $this->builder->where('nickname', 'like', "%{$keyword}%")->orWhere('username', 'like', "%{$keyword}%");
}
/**
* @param array $rangeTime
*
* @return \Illuminate\Database\Eloquent\Builder
*
* @author : stringer <10******56@qq.com>
* @datetime : 2020/11/24 10:35
*/
public function regisiterTime(array $regisiterTime)
{
return $this->builder->whereBetween('created_at', $regisiterTime);
}
/**
* @param $isActive
*
* @return \Illuminate\Database\Eloquent\Builder
*
* @author : stringer <10******56@qq.com>
* @datetime : 2020/11/24 10:35
*/
public function isActive($isActive)
{
return $this->builder->where('is_active', $this->str2Bool($isActive));
}
/**
* @param string $type
*
* @return \Illuminate\Database\Eloquent\Builder
*
* @author : stringer <10******56@qq.com>
* @datetime : 2020/11/24 10:35
*/
public function type(string $type)
{
return $this->builder->where('type', $type);
}
}
然后我们在控制器中使用:
<?php
namespace xxx;
use App\Filters\UserFilter;
use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Http\Request;
/**
* Class UserController
*
* @package App\Http\Controllers\Admin
*/
class UserController extends Controller
{
/**
* @param \Illuminate\Http\Request $request
* @param \App\Filters\UserFilter $filter
*
* @return \Illuminate\Http\JsonResponse
*
* @author : stringer <10******56@qq.com>
* @datetime : 2020/08/29 9:58
*/
public function index(Request $request, UserFilter $filter)
{
$users = User::filter($filter)->latest()->paginate($request->input("limit"));
return \response()->json($users);
}
如此一来我们的代码就很简洁了。把我们的所有筛选操作转移到了 UserFilter
。
还有一种情况就是基本只做个关键字筛选,我们定义一个 KeywordFilter
:
<?php
namespace App\Filters;
use Illuminate\Database\Eloquent\Builder;
/**
* Class KeywordFilter
*
* @package App\Filters
*/
class KeywordFilter extends Filter
{
/**
* @var string[]
*/
protected $filters = [
'keyword',
];
/**
* @var array
*/
protected $fields = [];
/**
* 设置想要搜索的字段
*
* @param string|array $field
*
* @return $this
*
* @author : stringer <10******56@qq.com>
* @datetime : 2020/11/26 14:29
*/
public function field($field)
{
$field = is_array($field) ? $field : func_get_args();
$this->fields = $field;
return $this;
}
/**
* 关键字筛选
*
* @param string|null $keyword 搜索关键字
*
* @return \Illuminate\Database\Eloquent\Builder
*
* @author : stringer <10******56@qq.com>
* @datetime : 2020/11/26 14:32
*/
protected function keyword(?string $keyword) : Builder
{
if (empty($this->fields)) {
return $this->builder;
}
return $this->builder->where(function (Builder $builder) use ($keyword) {
$fields = $this->fields;
$first = array_shift($fields);
$builder->where($first, "like", "%{$keyword}%");
if (!empty($fields)) {
foreach ($fields as $field) {
$builder->orWhere($field, "like", "%{$keyword}%");
}
}
});
}
}
使用:
<?php
namespace App\Http\Controllers\Admin;
use App\Filters\KeywordFilter;
use App\Http\Controllers\Controller;
use App\Http\Requests\AdminUserRequest;
use App\Models\AdminUser;
use Illuminate\Http\Request;
/**
* Class AdminUserController
*
* @package App\Http\Controllers\Admin
*/
class AdminUserController extends Controller
{
/**
* @param \Illuminate\Http\Request $request
* @param \App\Filters\KeywordFilter $filter
*
* @return \Illuminate\Http\JsonResponse
*
* @author : stringer <10******56@qq.com>
* @datetime : 2020/08/29 9:58
*/
public function index(Request $request, KeywordFilter $filter)
{
$adminUsers = AdminUser::filter($filter->field('username', 'nickname'))
->latest()
->paginate($request->input("limit"));
return \response()->json($adminUsers);
}
我们在 field
方法里面传入可以进行搜索的匹配的字段即可。
如此一来,如果说有很多张表需要筛选。我们就新增一个 XxxxFilter
。
如果一张表里面有很多个字段需要筛选,我们就在该 xxxFilter
下新增筛选方法即可。
本作品采用《CC 协议》,转载必须注明作者和本文链接
进阶版:github.com/Tucker-Eric/EloquentFil...