表格 - 过滤器
查询构造器
简介
查询构造器(Query Builder)允许你自定义一套复杂的条件,在表格中过滤数据。它能够处理无限嵌套条件,这就允许你使用 “and” 和 “or” 操作符进行分组。
要使用它,你需要定义一套用于过滤数据的”约束条件(constraints)“。Filament 包含了一些遵循通用数据类型的内置约束,不过你也可以自定义约束。
使用 QueryBuilder
过滤器,你可以将查询构造器添加到任何表格中:
use Filament\Tables\Filters\QueryBuilder;
use Filament\Tables\Filters\QueryBuilder\Constraints\BooleanConstraint;
use Filament\Tables\Filters\QueryBuilder\Constraints\DateConstraint;
use Filament\Tables\Filters\QueryBuilder\Constraints\NumberConstraint;
use Filament\Tables\Filters\QueryBuilder\Constraints\RelationshipConstraint;
use Filament\Tables\Filters\QueryBuilder\Constraints\RelationshipConstraint\Operators\IsRelatedToOperator;
use Filament\Tables\Filters\QueryBuilder\Constraints\SelectConstraint;
use Filament\Tables\Filters\QueryBuilder\Constraints\TextConstraint;
QueryBuilder::make()
->constraints([
TextConstraint::make('name'),
BooleanConstraint::make('is_visible'),
NumberConstraint::make('stock'),
SelectConstraint::make('status')
->options([
'draft' => 'Draft',
'reviewing' => 'Reviewing',
'published' => 'Published',
])
->multiple(),
DateConstraint::make('created_at'),
RelationshipConstraint::make('categories')
->multiple()
->selectable(
IsRelatedToOperator::make()
->titleAttribute('name')
->searchable()
->multiple(),
),
NumberConstraint::make('reviewsRating')
->relationship('reviews', 'rating')
->integer(),
])
当深度嵌套查询构造器时,你可能需要增加过滤器占用的空间数量。其中一个方式是,将过滤器放在表格内容之上:
use Filament\Tables\Enums\FiltersLayout;
use Filament\Tables\Filters\QueryBuilder;
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->filters([
QueryBuilder::make()
->constraints([
// ...
]),
], layout: FiltersLayout::AboveContent);
}
可用约束
Filament 随附了许多开箱即用的约束。你也可以创建自定义约束:
文本约束
文本约束(Text constraints)允许你过滤文本字段。可用于过滤任何文本字段,包括通过关联来的文本。
use Filament\Tables\Filters\QueryBuilder\Constraints\TextConstraint;
TextConstraint::make('name') // Filter the `name` column
TextConstraint::make('creatorName')
->relationship(name: 'creator', titleAttribute: 'name') // Filter the `name` column on the `creator` relationship
默认情况下,有如下一些可用操作符:
- Contains - 筛选包含搜索条件的字段
- Does not contain - 筛选不包含搜索条件的字段
- Starts with - 筛选以搜索条件为开头的列字段
- Does not start with - 筛选不以搜索条件为开头的列字段
- Ends with - 筛选以搜索条件为结尾的列字段
- Does not end with - 筛选不以搜索条件为结尾的列字段
- Equals - 筛选等于搜索词的列字段
- Does not equal - 筛选不等于搜索词的列字段
- Is filled - 筛选包含不为空的字段
- Is blank - 筛选包含值为空的字段
布尔值约束
布尔值约束(Boolean constraint)允许你过滤布尔值字段。可用于过滤任何布尔值字段,包括关联中的布尔值字段。
use Filament\Tables\Filters\QueryBuilder\Constraints\BooleanConstraint;
BooleanConstraint::make('is_visible') // Filter the `is_visible` column
BooleanConstraint::make('creatorIsAdmin')
->relationship(name: 'creator', titleAttribute: 'is_admin') // Filter the `is_admin` column on the `creator` relationship
默认情况下,以下操作符可用:
- Is true - 筛选值为
true
的字段 - Is false - 筛选值为
false
的字段
数值约束
数值约束(Number constraint)允许你过滤数值型字段。可用于过滤任何数值型字段,包括关联中的字段。
use Filament\Tables\Filters\QueryBuilder\Constraints\NumberConstraint;
NumberConstraint::make('stock') // Filter the `stock` column
NumberConstraint::make('ordersItemCount')
->relationship(name: 'orders', titleAttribute: 'item_count') // Filter the `item_count` column on the `orders` relationship
默认情况下,可以使用如下操作符:
- Is minimum - 筛选大于或等于所搜索数字的字段
- Is less than - 筛选小于所搜索数字的字段
- Is maximum - 筛选小于或等于所搜索数字的字段
- Is greater than - 筛选大于所搜索数字的字段
- Equals - 筛选等于所搜索数字的字段
- Does not equal - 筛选不等于所搜索数字的字段
- Is filled - 筛选不为空的字段
- Is blank - 筛选空值字段
当数值约束中使用 relationship()
时,用户也可以”聚合”关联记录。也就是说,可以过滤列字段使之一次性对所有关联记录求总和(sum)、求平均(average)、求最小值(minimum)或最大值(maximum)。
整型约束
默认情况下,数值约束允许使用小数。如果你只想允许整型值,可以使用 integer()
方法:
use Filament\Tables\Filters\QueryBuilder\Constraints\NumberConstraint;
NumberConstraint::make('stock')
->integer()
日期约束
日期约束(Date constraint)允许你过滤日期字段。可用于过滤任何日期字段,包括关联日期字段。
use Filament\Tables\Filters\QueryBuilder\Constraints\DateConstraint;
DateConstraint::make('created_at') // Filter the `created_at` column
DateConstraint::make('creatorCreatedAt')
->relationship(name: 'creator', titleAttribute: 'created_at') // Filter the `created_at` column on the `creator` relationship
默认情况下,可以使用如下操作符:
- Is after - 过滤字段使之在搜索日期之后
- Is not after - 过滤字段使之不在搜索日期之后,包括同一日期
- Is before - 过滤字段使之在搜索日期之前
- Is not before - 过滤字段使之不在搜索日期之前,包括同一日期
- Is date - 过滤字段使之与搜索日期相同
- Is not date - 过滤字段使之不同于搜索日期
- Is month - 过滤字段使之与所选月份相同
- Is not month - 过滤字段使之与所选月份不同
- Is year - 过滤字段使之与所选年份相同
- Is not year - 过滤字段使之与所选年份不同
Select 约束
Select constraint 允许你使用 Select 字段过滤字段。可用于过滤任何字段,包括来自关联的字段。
use Filament\Tables\Filters\QueryBuilder\Constraints\SelectConstraint;
SelectConstraint::make('status') // Filter the `status` column
->options([
'draft' => 'Draft',
'reviewing' => 'Reviewing',
'published' => 'Published',
])
SelectConstraint::make('creatorStatus')
->relationship(name: 'creator', titleAttribute: 'department') // Filter the `department` column on the `creator` relationship
->options([
'sales' => 'Sales',
'marketing' => 'Marketing',
'engineering' => 'Engineering',
'purchasing' => 'Purchasing',
])
可搜索 Select 约束
默认情况下,Select 约束不允许用户搜索选项。如果你想允许用户搜索选项,请使用 searchable()
方法:
use Filament\Tables\Filters\QueryBuilder\Constraints\SelectConstraint;
SelectConstraint::make('status')
->searchable()
->options([
'draft' => 'Draft',
'reviewing' => 'Reviewing',
'published' => 'Published',
])
多选约束
默认情况下,Select 约束只允许用户选择一个选项。如果你希望允许用户选择多个选项,请使用 multiple()
方法:
use Filament\Tables\Filters\QueryBuilder\Constraints\SelectConstraint;
SelectConstraint::make('status')
->multiple()
->options([
'draft' => 'Draft',
'reviewing' => 'Reviewing',
'published' => 'Published',
])
当用户选择多个选项时,表格会过滤以显示匹配任何一个所选选项的记录。
关联约束
关联约束(Relationship constraint)允许你使用关联数据过滤字段:
use Filament\Tables\Filters\QueryBuilder\Constraints\RelationshipConstraint;
use Filament\Tables\Filters\QueryBuilder\Constraints\RelationshipConstraint\Operators\IsRelatedToOperator;
RelationshipConstraint::make('creator') // Filter the `creator` relationship
->selectable(
IsRelatedToOperator::make()
->titleAttribute('name')
->searchable()
->multiple(),
)
IsRelatedToOperator
用于配置 “Is / Contains” 和 “Is not / Does not contain” 操作符。它提供了一个 Select 字段,允许用户过滤附加记录的关联。titleAttribute()
方法用于指定应使用哪个属性来识别列表中的每个关联记录。searchable()
方法使列表可搜索。multiple()
方法允许用户选择多个关联记录,如果选择了,表格将被过滤用以显示与所选任何关联记录匹配的记录。
多关联
默认情况下,关联约束只引入适用的操作符,用于过滤单一关联,比如 BelongsTo
。如果你使用诸如 HasMany
或 BelongsToMany
这样的关联,你可以将约束标记为 multiple()
:
use Filament\Tables\Filters\QueryBuilder\Constraints\RelationshipConstraint;
RelationshipConstraint::make('categories')
->multiple()
这会将如下操作符添加到约束:
- Has minimum - 过滤字段,使之至少有指定数量的关联记录
- Has less than - 过滤字段,使之拥有少于指定数量的关联记录
- Has maximum - 过滤字段,使之最多用有指定数量的关联记录
- Has more than - 过滤字段,使之拥有多于指定数量的关联记录
- Has - 过滤字段,使之拥有指定数量的关联记录
- Does not have - 过滤字段,使之没有指定数量的关联记录
空关联约束
RelationshipConstraint
和其他约束一样不支持 nullable()
。
如果关联为 multiple()
,那么约束会展示一个选项以过滤空关联。这意味着关联没有相关记录。如果关联是单一的,可以使用 emptyable()
方法展示一个用以过滤空关联的选项。
use Filament\Tables\Filters\QueryBuilder\Constraints\RelationshipConstraint;
RelationshipConstraint::make('creator')
->emptyable()
如果你的 multiple()
关联必须至少有一个关联记录,那么你可以使用 emptyable(false)
来因此过滤掉空关联的选项:
use Filament\Tables\Filters\QueryBuilder\Constraints\RelationshipConstraint;
RelationshipConstraint::make('categories')
->emptyable(false)
Nullable 约束
默认情况下,约束不会显示用于筛选 null
值的选项。如果你想显示筛选 null
值的选项,可以使用 nullable()
方法:
use Filament\Tables\Filters\QueryBuilder\Constraints\TextConstraint;
TextConstraint::make('name')
->nullable()
以下是可用操作符:
- Is filled - 过滤字段使之非空
- Is blank - 过滤字段使之为空
关联查询范围设置
在约束中使用 relationship()
方法时,你可以使用 modifyQueryUsing
参数设置查询范围,以过滤关联记录:
use Filament\Tables\Filters\QueryBuilder\Constraints\TextConstraint;
use Illuminate\Database\Eloquent\Builder;
TextConstraint::make('adminCreatorName')
->relationship(
name: 'creator',
titleAttribute: 'name',
modifyQueryUsing: fn (Builder $query) => $query->where('is_admin', true),
)
自定义约束图标
每个约束类型都有一个默认的[图标]](../../styling/icons),它显示在选择器标签旁边。你可以将图标名传递给 icon()
方法自定义约束图标。
use Filament\Tables\Filters\QueryBuilder\Constraints\TextConstraint;
TextConstraint::make('author')
->relationship(name: 'author', titleAttribute: 'name')
->icon('heroicon-m-user')
重写默认操作符
每个约束都有一组默认的操作符,你可以使用 opearator()
方法对其进行自定义:
use Filament\Tables\Filters\QueryBuilder\Constraints\Operators\IsFilledOperator;
use Filament\Tables\Filters\QueryBuilder\Constraints\TextConstraint;
TextConstraint::make('author')
->relationship(name: 'author', titleAttribute: 'name')
->operators([
IsFilledOperator::make(),
])
这将移除所有操作符,并注册 EqualsOperator
。
如果你想将新操作符添加到列表末尾中,请使用 pushOperators()
:
use Filament\Tables\Filters\QueryBuilder\Constraints\Operators\IsFilledOperator;
use Filament\Tables\Filters\QueryBuilder\Constraints\TextConstraint;
TextConstraint::make('author')
->relationship(name: 'author', titleAttribute: 'name')
->pushOperators([
IsFilledOperator::class,
])
如果你想将新操作符添加到列表开头中,请使用 unshiftOperators()
:
use Filament\Tables\Filters\QueryBuilder\Constraints\Operators\IsFilledOperator;
use Filament\Tables\Filters\QueryBuilder\Constraints\TextConstraint;
TextConstraint::make('author')
->relationship(name: 'author', titleAttribute: 'name')
->unshiftOperators([
IsFilledOperator::class,
])
创建自定义约束
使用 Constraint::make()
方法,自定义约束可以和其他约束内联(inline)创建。你也可以将图标传递给 icon()
方法:
use Filament\Tables\Filters\QueryBuilder\Constraints\Constraint;
Constraint::make('subscribed')
->icon('heroicon-m-bell')
->operators([
// ...
]),
如果你想自定义约束的标签,请使用 label()
方法:
use Filament\Tables\Filters\QueryBuilder\Constraints\Constraint;
Constraint::make('subscribed')
->label('Subscribed to updates')
->icon('heroicon-m-bell')
->operators([
// ...
]),
现在,你必须为该约束定义操作符。你可以从这些选项中进行选择以过滤列字段。如果列字段是 nullable,你也可以为自定义约束注册内置运算符:
use Filament\Tables\Filters\QueryBuilder\Constraints\Constraint;
use Filament\Tables\Filters\QueryBuilder\Constraints\Operators\IsFilledOperator;
Constraint::make('subscribed')
->label('Subscribed to updates')
->icon('heroicon-m-bell')
->operators([
// ...
IsFilledOperator::class,
]),
创建自定义操作符
使用 Operator::make()
方法,可以创建自定义操作符:
use Filament\Tables\Filters\QueryBuilder\Constraints\Operators\Operator;
Operator::make('subscribed')
->label(fn (bool $isInverse): string => $isInverse ? 'Not subscribed' : 'Subscribed')
->summary(fn (bool $isInverse): string => $isInverse ? 'You are not subscribed' : 'You are subscribed')
->baseQuery(fn (Builder $query, bool $isInverse) => $query->{$isInverse ? 'whereDoesntHave' : 'whereHas'}(
'subscriptions.user',
fn (Builder $query) => $query->whereKey(auth()->user()),
)),
本例中,操作符能够基于认证用户是否订阅该记录来过滤记录。订阅在表格的 subscriptions
关联中重新排序。
baseQuery()
方法用于定义过滤记录的查询。当选中 “Subscribed” 选项时,$isInverse
参数为 false
,而选中 Not subscribed
选项时,则为 true
。该函数应用于表格的基础查询,其中可以使用 whereHas()
。如果函数不需要应用到表格的基础查询,比如使用简单的 where()
或 whereIn()
,你可以使用 query()
方法取代,它的好处是能够在嵌套的 “OR” 分组中使用。
label()
方法用于渲染操作符下拉菜单的选项。每个操作符注册了两个选项,一个用于操作符不是 is Inverse 时,一个用在 is Inverse 时。
当 summary()
方法应用到查询时,它用在约束的 header 中,以提供该激活约束的概览。
自定义约束选择器
在约束选择器中修改列数
约束选择器(Constraint Picker)只有 1 列。通过将列数传递给 constraintPickerColumns()
可以自定义列数:
use Filament\Tables\Filters\QueryBuilder;
QueryBuilder::make()
->constraintPickerColumns(2)
->constraints([
// ...
])
该方法可以通过不同方式使用:
- 你可以传递整型比如
constraintPickerColumns(2)
。该整数为lg
临界点及以上宽度时的列数。比此小的设备,只会占 1 列。 - 你可以传递一个数组,其中键是临界点(breakpoint)、而值为列数。比如,
constraintPickerColumns(['md' => 2, 'xl' => 4])
将会在中等(medium)设备中创建 2 列布局,在超大设备中,创建 4 列布局。而较小(smaller)的设备的默认临界点使用 1 列布局,除非你使用了default
数组键。
临界点(sm
、md
、lg
、xl
、2xl
)是由 Tailwind 定义,可以在 Tailwind 文档中查看。
增加约束选择器的宽度
当增加列数时,下拉列表的宽度应该逐步增加以处理额外的列数。如果你想要更多的控制,可以使用 constraintPickerWidth()
方法手动设置下拉列表的最大宽度。选项对应于 Tailwind 的 max-width 刻度。可选宽度为 xs
、sm
、md
、lg
、xl
、2xl
、3xl
、4xl
、5xl
、6xl
、7xl
:
use Filament\Tables\Filters\QueryBuilder;
QueryBuilder::make()
->constraintPickerColumns(3)
->constraintPickerWidth('2xl')
->constraints([
// ...
])
Edit on GitHubStill need help? Join our Discord community or open a GitHub discussion