查询过滤

model-grid提供了一系列的方法实现表格数据的查询过滤:

  1. // 禁用
  2. $grid->disableFilter();
  3. // 显示
  4. $grid->showFilter();
  5. // 禁用过滤器按钮
  6. $grid->disableFilterButton();
  7. // 显示过滤器按钮
  8. $grid->showFilterButton();
  9. $grid->filter(function($filter){
  10. // 展开过滤器
  11. $filter->expand();
  12. // 在这里添加字段过滤器
  13. $filter->equal('id', '产品序列号');
  14. $filter->like('name', 'name');
  15. ...
  16. });

过滤器布局

默认布局方式为rightSide

{tip} Since v1.2.0

rightSide

  1. use Dcat\Admin\Grid;
  2. $grid->filter(function (Grid\Filter $filter) {
  3. // 更改为 rightSide 布局
  4. $grid->rightSide();
  5. ...
  6. });

效果

查询过滤 - 图1

panel

  1. use Dcat\Admin\Grid;
  2. $grid->filter(function (Grid\Filter $filter) {
  3. // 更改为 panel 布局
  4. $filter->panel();
  5. // 注意切换为panel布局方式时需要重新调整表单字段的宽度
  6. $filter->equal('id')->width(3);
  7. });

效果

查询过滤 - 图2

自定义布局 (view)

{tip} Since v1.5.2

如果以上的布局无法满足需求,可以通过view方法自定义过滤器模板

  1. $grid->filter(function ($filter) {
  2. $filter->view('xxx');
  3. ...
  4. });

查询类型

目前支持的过滤类型有下面这些:

equal

sql: ... WHEREcolumn= "$input"

  1. $filter->equal('column', $label);

notEqual

sql: ... WHEREcolumn!= "$input"

  1. $filter->notEqual('column', $label);

like

sql: ... WHEREcolumnLIKE "%$input%"

  1. $filter->like('column', $label);

ilike

sql: ... WHEREcolumnILIKE "%$input%"

  1. $filter->ilike('column', $label);

startWith

sql: ... WHEREcolumnLIKE "$input%"

  1. $filter->startWith('column', $label);
  2. // 如果需要使用“ilike”
  3. $filter->startWith('column', $label)->ilike();

endWith

sql: ... WHEREcolumnLIKE "%$input"

  1. $filter->endWith('column', $label);
  2. // 如果需要使用“ilike”
  3. $filter->endWith('column', $label)->ilike();

gt

sql: ... WHEREcolumn> "$input"

  1. $filter->gt('column', $label);

lt

sql: ... WHEREcolumn< "$input"

  1. $filter->lt('column', $label);

ngt

sql: ... WHEREcolumn<= "$input"

  1. $filter->ngt('column', $label);

nlt

sql: ... WHEREcolumn>= "$input"

  1. $filter->nlt('column', $label);

between

sql: ... WHEREcolumnBETWEEN "$start" AND "$end"

  1. $filter->between('column', $label);
  2. // 设置datetime类型
  3. $filter->between('column', $label)->datetime();
  4. // 设置time类型
  5. $filter->between('column', $label)->time();

in

sql: ... WHEREcolumnin (...$inputs)

  1. $filter->in('column', $label)->multipleSelect(['key' => 'value']);

notIn

sql: ... WHEREcolumnnot in (...$inputs)

  1. $filter->notIn('column', $label)->multipleSelect(['key' => 'value']);

date

sql: ... WHERE DATE(column) = "$input"

  1. $filter->date('column', $label);

day

sql: ... WHERE DAY(column) = "$input"

  1. $filter->day('column', $label);

month

sql: ... WHERE MONTH(column) = "$input"

  1. $filter->month('column', $label);

year

sql: ... WHERE YEAR(column) = "$input"

  1. $filter->year('column', $label);

复杂查询where

可以用where来构建比较复杂的查询过滤

sql: ... WHEREtitleLIKE "%$input" ORcontentLIKE "%$input"

  1. $filter->where('search', function ($query) {
  2. $query->where('title', 'like', "%{$this->input}%")
  3. ->orWhere('content', 'like', "%{$this->input}%");
  4. });

sql: ... WHERErate>= 6 ANDcreated_at= {$input}:

  1. $filter->where('Text', function ($query) {
  2. $query->whereRaw("`rate` >= 6 AND `created_at` = {$this->input}");
  3. });

关系查询,查询对应关系profile的字段:

  1. $filter->where('mobile', function ($query) {
  2. $query->whereHas('profile', function ($query) {
  3. $query->where('address', 'like', "%{$this->input}%")->orWhere('email', 'like', "%{$this->input}%");
  4. });
  5. }, '地址或手机号');

复杂范围查询whereBetween

{tip} Since v1.6.5

通过whereBetween可以自定义范围查询

  1. $filter->whereBetween('created_at', function ($q) {
  2. $start = $this->input['start'] ?? null;
  3. $end = $this->input['end'] ?? null;
  4. $q->whereHas('goods', function ($q) use ($start) {
  5. if ($start !== null) {
  6. $q->where('price', '>=', $start);
  7. }
  8. if ($end !== null) {
  9. $q->where('price', '<=', $end);
  10. }
  11. });
  12. });

同时这个方法也支持时间日期范围查询

  1. $filter->whereBetween('created_at', function ($q) {
  2. ...
  3. })->datetime();

过滤器组group

有时候对同一个字段要设置多种筛选方式,可以通过下面的方式实现

  1. $filter->group('rate', function ($group) {
  2. $group->gt('大于');
  3. $group->lt('小于');
  4. $group->nlt('不小于');
  5. $group->ngt('不大于');
  6. $group->equal('等于');
  7. });

有下面的几个方法可以调用

  1. // 等于
  2. $group->equal();
  3. // 不等于
  4. $group->notEqual();
  5. // 大于
  6. $group->gt();
  7. // 小于
  8. $group->lt();
  9. // 大于等于
  10. $group->nlt();
  11. // 小于等于
  12. $group->ngt();
  13. // 匹配
  14. $group->match();
  15. // 复杂条件
  16. $group->where();
  17. // like查询
  18. $group->like();
  19. // like查询
  20. $group->contains();
  21. // ilike查询
  22. $group->ilike();
  23. // 以输入的内容开头
  24. $group->startWith();
  25. // 以输入的内容结尾
  26. $group->endWith();

范围查询scope

可以把你最常用的查询定义为一个查询范围,它将会出现在筛选按钮的下拉菜单中,下面是几个例子:

  1. $filter->scope('male', '男性')->where('gender', 'm');
  2. // 多条件查询
  3. $filter->scope('new', '最近修改')
  4. ->whereDate('created_at', date('Y-m-d'))
  5. ->orWhere('updated_at', date('Y-m-d'));
  6. // 关联关系查询
  7. $filter->scope('address')->whereHas('profile', function ($query) {
  8. $query->whereNotNull('address');
  9. });
  10. $filter->scope('trashed', '被软删除的数据')->onlyTrashed();

scope方法第一个参数为查询的key, 会出现的url参数中,第二个参数是下拉菜单项的label, 如果不填,第一个参数会作为label显示

scope方法可以链式调用任何eloquent查询条件,效果参考Demo

表单类型

text

表单类型默认是text input,可以设置placeholder

  1. $filter->equal('column')->placeholder('请输入。。。');

也可以通过下面的一些方法来限制用户输入格式:

  1. $filter->equal('column')->url();
  2. $filter->equal('column')->email();
  3. $filter->equal('column')->integer();
  4. $filter->equal('column')->ip();
  5. $filter->equal('column')->mac();
  6. $filter->equal('column')->mobile();
  7. // $options 参考 https://github.com/RobinHerbots/Inputmask/blob/4.x/README_numeric.md
  8. $filter->equal('column')->decimal($options = []);
  9. // $options 参考 https://github.com/RobinHerbots/Inputmask/blob/4.x/README_numeric.md
  10. $filter->equal('column')->currency($options = []);
  11. // $options 参考 https://github.com/RobinHerbots/Inputmask/blob/4.x/README_numeric.md
  12. $filter->equal('column')->percentage($options = []);
  13. // $options 参考 https://github.com/RobinHerbots/Inputmask, $icon为input前面的图标
  14. $filter->equal('column')->inputmask($options = [], $icon = 'pencil');

弹窗选择器(selectResource)

{tip} 此功能即将在 2.0 版本中废弃,请使用 selectTable

选择数据源,选择弹窗里面的表格数据。

  1. // 单选
  2. $filter->equal('user_id')
  3. ->selectResource('pages/users')
  4. ->placeholder('请选择。。。')
  5. ->options(function ($v) { // options方法用于显示已选中的值
  6. if (!$v) return $v;
  7. $userModel = config('admin.database.users_model');
  8. return $userModel::find($v)->pluck('name', 'id');
  9. });
  10. // 多选
  11. $filter->in('user_id')
  12. ->selectResource('pages/users')
  13. ->multiple(3) // 最多选择3个选项,不传则不限制
  14. ->options(function ($v) { // options方法用于显示已选中的值
  15. if (!$v) return $v;
  16. $userModel = config('admin.database.users_model');
  17. return $userModel::find($v)->pluck('name', 'id');
  18. });

查询过滤 - 图3

然后设置你的路由app/Admin/routes.php

  1. $router->resource('pages/users', 'UserController');

pages/users页面实现:

  1. <?php
  2. use Dcat\Admin\Models\Administrator;
  3. use Dcat\Admin\IFrameGrid;
  4. use Dcat\Admin\Grid;
  5. use Dcat\Admin\Controllers\AdminController;
  6. class UserController extends AdminController
  7. {
  8. protected function iFrameGrid()
  9. {
  10. $grid = new IFrameGrid(new Administrator());
  11. // 指定行选择器选中时显示的值的字段名称
  12. // 指定行选择器选中时显示的值的字段名称
  13. // 指定行选择器选中时显示的值的字段名称
  14. // 如果表格数据中带有 “name”、“title”或“username”字段,则可以不用设置
  15. $grid->rowSelector()->titleColumn('username');
  16. $grid->id->sortable();
  17. $grid->username;
  18. $grid->name;
  19. $grid->filter(function (Grid\Filter $filter) {
  20. $filter->equal('id');
  21. $filter->like('username');
  22. $filter->like('name');
  23. });
  24. return $grid;
  25. }
  26. }

表格选择器 (selectTable)

{tip} Since v1.7.0 此功能可用于替代弹窗选择器弹窗选择器即将在2.0版本中废弃

  1. use App\Admin\Renderable\UserTable;
  2. use Dcat\Admin\Models\Administrator;
  3. $filter->equal('user_id')
  4. ->selectTable(UserTable::make(['id' => ...])) // 设置渲染类实例,并传递自定义参数
  5. ->title('弹窗标题')
  6. ->dialogWidth('50%') // 弹窗宽度,默认 800px
  7. ->model(Administrator::class, 'id', 'name'); // 设置编辑数据显示
  8. // 上面的代码等同于
  9. $filter->equal('user_id')
  10. ->selectTable(UserTable::make(['id' => ...])) // 设置渲染类实例,并传递自定义参数
  11. ->options(function ($v) { // 设置编辑数据显示
  12. if (! $v) {
  13. return [];
  14. }
  15. return Administrator::find($v)->pluck('name', 'id');
  16. });

定义渲染类如下,需要继承Dcat\Admin\Grid\LazyRenderable

{tip} 这里使用了数据表格异步加载功能,详细用法请参考异步加载

  1. <?php
  2. namespace App\Admin\Renderable;
  3. use Dcat\Admin\Grid;
  4. use Dcat\Admin\Grid\LazyRenderable;
  5. use Dcat\Admin\Models\Administrator;
  6. class UserTable extends LazyRenderable
  7. {
  8. public function grid(): Grid
  9. {
  10. // 获取外部传递的参数
  11. $id = $this->id;
  12. return Grid::make(new Administrator(), function (Grid $grid) {
  13. $grid->column('id');
  14. $grid->column('username');
  15. $grid->column('name');
  16. $grid->column('created_at');
  17. $grid->column('updated_at');
  18. // 指定行选择器选中时显示的值的字段名称
  19. // 指定行选择器选中时显示的值的字段名称
  20. // 指定行选择器选中时显示的值的字段名称
  21. // 如果表格数据中带有 “name”、“title”或“username”字段,则可以不用设置
  22. $grid->rowSelector()->titleColumn('username');
  23. $grid->quickSearch(['id', 'username', 'name']);
  24. $grid->paginate(10);
  25. $grid->disableActions();
  26. $grid->filter(function (Grid\Filter $filter) {
  27. $filter->like('username')->width(4);
  28. $filter->like('name')->width(4);
  29. });
  30. });
  31. }
  32. }

多选 (multipleSelectTable)

多选的用法与上述selectTable方法一致

  1. $filter->in('user_id')
  2. ->multipleSelectTable(UserTable::make(['id' => $form->getKey()])) // 设置渲染类实例,并传递自定义参数
  3. ->max(10) // 最多选择 10 个选项,不传则不限制
  4. ->model(Administrator::class, 'id', 'name'); // 设置编辑数据显示

select

  1. $filter->equal('column')->select(['key' => 'value'...]);
  2. // 或者从api获取数据,api的格式参考model-form的select组件
  3. $filter->equal('column')->select('api/users');

multipleSelect

一般用来配合innotIn两个需要查询数组的查询类型使用,也可以在where类型的查询中使用:

  1. $filter->in('column')->multipleSelect(['key' => 'value'...]);
  2. // 或者从api获取数据,api的格式参考model-form的multipleSelect组件
  3. $filter->in('column')->multipleSelect('api/users');

datetime

通过日期时间组件来查询,$options的参数和值参考bootstrap-datetimepicker

  1. $filter->equal('column')->datetime($options);
  2. // `date()` 相当于 `datetime(['format' => 'YYYY-MM-DD'])`
  3. $filter->equal('column')->date();
  4. // `time()` 相当于 `datetime(['format' => 'HH:mm:ss'])`
  5. $filter->equal('column')->time();
  6. // `day()` 相当于 `datetime(['format' => 'DD'])`
  7. $filter->equal('column')->day();
  8. // `month()` 相当于 `datetime(['format' => 'MM'])`
  9. $filter->equal('column')->month();
  10. // `year()` 相当于 `datetime(['format' => 'YYYY'])`
  11. $filter->equal('column')->year();

如果你的时间日期字段在数据库中存储的是时间戳类型,那么可以通过toTimestamp方法把表单的值转化为时间戳

  1. $filter->equal('column')->datetime($options)->toTimestamp();

常用方法

过滤器宽度 (width)

  1. // 设置为“1-12”之间的值,默认值是“3”
  2. $filter->equal('column')->width(3);
  3. // 也可以写死宽度
  4. $filter->equal('column')->width('250px');

设置默认值 (default)

  1. $filter->equal('column')->default('text');
  2. $filter->equal('column')->select([0 => 'PHP', 1 => 'Java'])->default(1);

展开过滤器 (expand)

  1. $filter->expand();
  2. $filter->equal('column');
  3. ...

不显示过滤器input输入框的边框

  1. $filter->withoutInputBorder();
  2. $filter->equal('column');
  3. ...

设置过滤器容器样式

  1. $filter->style('padding:0');
  2. $filter->equal('column');
  3. ...

设置过滤器容器padding

  1. $filter->padding('10px', '10px', '10px', '10px');
  2. $filter->equal('column');
  3. ...

忽略筛选项 (ignore)

{tip} Since v1.7.0

通过ignore方法可以在提交表单时忽略当前筛选项

  1. $filter->equal('column')->ignore();

关联关系字段查询

{tip} Since v1.5.0

假设你的模型如下

  1. class User extends Model
  2. {
  3. public function profile()
  4. {
  5. return $this->hasOne(...);
  6. }
  7. public function myPosts()
  8. {
  9. return $this->hasMany(...);
  10. }
  11. }

通过下面的方法可以查询profiles表的first_name字段以及posts表的title字段

  1. $grid->filter(function ($filter) {
  2. $filter->like('profile.first_name');
  3. $filter->like('myPosts.title');
  4. });

{tip} Since v1.7.0

如果安装了 dcat/laravel-wherehasin,则会优先使用whereHasIn方法进行查询操作

自定义过滤器

下面通过between的实现来讲解下怎么自定义过滤器。

首先新建一个过滤器类继承Dcat\Admin\Grid\Filter\AbstractFilter

  1. <?php
  2. namespace Dcat\Admin\Grid\Filter;
  3. use Dcat\Admin\Admin;
  4. use Dcat\Admin\Grid\Filter\Presenter\DateTime;
  5. use Illuminate\Support\Arr;
  6. class Between extends AbstractFilter
  7. {
  8. // 自定义你的过滤器显示模板
  9. protected $view = 'admin::filter.between';
  10. // 这个方法用于生成过滤器字段的唯一id
  11. // 通过这个唯一id则可以用js代码对其进行操作
  12. public function formatId($column)
  13. {
  14. $id = str_replace('.', '_', $column);
  15. $name = $this->parent->getGrid()->getName();
  16. return ['start' => "{$name}{$id}_start", 'end' => "{$name}{$id}_end"];
  17. }
  18. // form表单name属性格式化
  19. protected function formatName($column)
  20. {
  21. $columns = explode('.', $column);
  22. if (count($columns) == 1) {
  23. $name = $columns[0];
  24. } else {
  25. $name = array_shift($columns);
  26. foreach ($columns as $column) {
  27. $name .= "[$column]";
  28. }
  29. }
  30. return ['start' => "{$name}[start]", 'end' => "{$name}[end]"];
  31. }
  32. // 创建条件
  33. // 这里构建的条件支持`Laravel query builder`即可。
  34. public function condition($inputs)
  35. {
  36. if (!Arr::has($inputs, $this->column)) {
  37. return;
  38. }
  39. $this->value = Arr::get($inputs, $this->column);
  40. $value = array_filter($this->value, function ($val) {
  41. return $val !== '';
  42. });
  43. if (empty($value)) {
  44. return;
  45. }
  46. if (!isset($value['start']) && isset($value['end'])) {
  47. // 这里返回的数组相当于
  48. // $query->where($this->column, '<=', $value['end']);
  49. return $this->buildCondition($this->column, '<=', $value['end']);
  50. }
  51. if (!isset($value['end']) && isset($value['start'])) {
  52. // 这里返回的数组相当于
  53. // $query->where($this->column, '>=', $value['end']);
  54. return $this->buildCondition($this->column, '>=', $value['start']);
  55. }
  56. $this->query = 'whereBetween';
  57. // 这里返回的数组相当于
  58. // $query->whereBetween($this->column, $value['end']);
  59. return $this->buildCondition($this->column, $this->value);
  60. }
  61. // 自定义过滤器表单显示方式
  62. public function datetime($options = [])
  63. {
  64. $this->view = 'admin::filter.betweenDatetime';
  65. DateTime::collectAssets();
  66. $this->setupDatetime($options);
  67. return $this;
  68. }
  69. protected function setupDatetime($options = [])
  70. {
  71. $options['format'] = Arr::get($options, 'format', 'YYYY-MM-DD HH:mm:ss');
  72. $options['locale'] = Arr::get($options, 'locale', config('app.locale'));
  73. $startOptions = json_encode($options);
  74. $endOptions = json_encode($options + ['useCurrent' => false]);
  75. // 通过上面格式化后的id对表单进行你想要的操作
  76. $script = <<<JS
  77. $('#{$this->id['start']}').datetimepicker($startOptions);
  78. $('#{$this->id['end']}').datetimepicker($endOptions);
  79. $("#{$this->id['start']}").on("dp.change", function (e) {
  80. $('#{$this->id['end']}').data("DateTimePicker").minDate(e.date);
  81. });
  82. $("#{$this->id['end']}").on("dp.change", function (e) {
  83. $('#{$this->id['start']}').data("DateTimePicker").maxDate(e.date);
  84. });
  85. JS;
  86. Admin::script($script);
  87. }
  88. }

admin::filter.between模板内容如下:

  1. <div class="filter-input col-sm-{{ $width }} " style="{!! $style !!}">
  2. <div class="form-group" >
  3. <div class="input-group input-group-sm">
  4. <span class="input-group-addon"><b>{!! $label !!}</b></span>
  5. <input type="text" class="form-control" placeholder="{{$label}}" name="{{$name['start']}}" value="{{ request($name['start'], \Illuminate\Support\Arr::get($value, 'start')) }}">
  6. <span class="input-group-addon" style="border-left: 0; border-right: 0;">To</span>
  7. <input type="text" class="form-control" placeholder="{{$label}}" name="{{$name['end']}}" value="{{ request($name['end'], \Illuminate\Support\Arr::get($value, 'end')) }}">
  8. </div>
  9. </div>
  10. </div>

admin::filter.betweenDatetime模板内容如下:

  1. <div class="filter-input col-sm-{{ $width }}" style="{!! $style !!}">
  2. <div class="form-group">
  3. <div class="input-group input-group-sm">
  4. <span class="input-group-addon"><b>{{$label}}</b> &nbsp;<i class="fa fa-calendar"></i></span>
  5. <input type="text" class="form-control" id="{{$id['start']}}" placeholder="{{$label}}" name="{{$name['start']}}" value="{{ request($name['start'], \Illuminate\Support\Arr::get($value, 'start')) }}">
  6. <span class="input-group-addon" style="border-left: 0; border-right: 0;">To</span>
  7. <input type="text" class="form-control" id="{{$id['end']}}" placeholder="{{$label}}" name="{{$name['end']}}" value="{{ request($name['end'], \Illuminate\Support\Arr::get($value, 'end')) }}">
  8. </div>
  9. </div>
  10. </div>

现在只要调用extend方法可以使用了,打开app/Admin/bootstrap.php,加入以下代码:

  1. Filter::extend('customBetween', Filter\Between::class);

使用:

扩展过滤器方法后IDE默认是不会自动补全的,这时候可以通过php artisan admin:ide-helper生成IDE提示文件。

  1. $filter->customBetween('created_at')->datetime();