跳到主要内容
版本:3.0

过滤器

概述

过滤器(Filter)允许你在数据上定义特定的约束,并允许用户限定查询范围,以查找他们所需的信息。可以在 $table->filters() 方法中定义过滤器:

use Filament\Tables\Table;

public function table(Table $table): Table
{
return $table
->filters([
// ...
]);
}
Table with filter

过滤器可以使用静态的 make() 方法创建,并传入其唯一名。然后你应该传入一个回调函数到 query() 中,设置过滤器的查询范围:

use Filament\Tables\Filters\Filter;
use Illuminate\Database\Eloquent\Builder;

Filter::make('is_featured')
->query(fn (Builder $query): Builder => $query->where('is_featured', true))

设置标签

默认情况下,过滤器的标签是有过滤器名生成。你可以使用 label() 方法自定义该标签:

use Filament\Tables\Filters\Filter;

Filter::make('is_featured')
->label('Featured')

可选地,你可以使用 translateLabel() 方法,使其利用 Laravel 的本地化特性自动翻译标签。

use Filament\Tables\Filters\Filter;

Filter::make('is_featured')
->translateLabel() // Equivalent to `label(__('Is featured'))`

自定义过滤器表单

默认情况下,使用 Filter 类创建过滤器会渲染一个 Chcekbox 表单组件。当 Checkbox 被勾选后,query() 函数将会使用表格的查询,过滤表格中的记录。如果 Checkbox 未被勾选,query() 函数会从表格查询中删除。

过滤器完全是建立在 Filament 表单字段之上。他们可以渲染任何表单字段的组合,使用户可以直接交互过滤表格。

使用 Toggle 按钮代替 Checbox

管理用于过滤器的表单字段的最简单示例是,使用 Toggle 按钮替换 Checkbox

use Filament\Tables\Filters\Filter;

Filter::make('is_featured')
->toggle()
Table with toggle filter

默认使用过滤器

使用 default() 方法,你可以设置默认启用过滤器:

use Filament\Tables\Filters\Filter;

Filter::make('is_featured')
->default()

Select 过滤器

有时候,你会使用 Select 字段而非 Checkbox。当您希望用户可以根据一组预定义选项过滤列字段时,尤其如此。为此,您可以使用 SelectFilter 类创建一个过滤器:

use Filament\Tables\Filters\SelectFilter;

SelectFilter::make('status')
->options([
'draft' => 'Draft',
'reviewing' => 'Reviewing',
'published' => 'Published',
])

通过 options() 传递给过滤器的选项,与传递给 Select 字段的方式一致:

自定义 SelectFilter 使用的列字段

SelectFilter 不需要自定义 query() 方法。查询所使用的列字段名是过滤器名称。要自定义字段名,请使用 attribute() 方法:

use Filament\Tables\Filters\SelectFilter;

SelectFilter::make('status')
->options([
'draft' => 'Draft',
'reviewing' => 'Reviewing',
'published' => 'Published',
])
->attribute('status_id')

多选 SelectFilter

这将允许用户选择多个选项,应用到过滤器。比如,状态过滤器可能向用户展示一些状态选项供用户选取及表格过滤使用。当用户选择多个选项时,表格会过滤显示匹配所选选项的记录。你可以使用 multiple() 方法启用该行为:

use Filament\Tables\Filters\SelectFilter;

SelectFilter::make('status')
->multiple()
->options([
'draft' => 'Draft',
'reviewing' => 'Reviewing',
'published' => 'Published',
])

关联 SelectFilter

SelectFilter 也能够基于关联自动填充。比如,如果表有一个 author 关联,它有一个 name 字段,你可以使用 relationship() 过滤属于某个作者(author)的记录:

use Filament\Tables\Filters\SelectFilter;

SelectFilter::make('author')
->relationship('author', 'name')

预加载 SelectFilter 关联选项

如果你想在页面加载时填充可搜索选项,而不是在用户搜索时加载,你可以使用 preload() 方法:

use Filament\Tables\Filters\SelectFilter;

SelectFilter::make('author')
->relationship('author', 'name')
->searchable()
->preload()
自定义 SelectFilter 关联查询

使用 relationship() 方法的第三个参数,你可以自定义用于检索选项的数据库查询:

use Filament\Tables\Filters\SelectFilter;
use Illuminate\Database\Eloquent\Builder;

SelectFilter::make('author')
->relationship('author', 'name', fn (Builder $query) => $query->withTrashed())

搜索 SelectFilter 选项

使用 searchable() 方法,你可以启用搜索输入框,以方便访问选项:

use Filament\Tables\Filters\SelectFilter;

SelectFilter::make('author')
->relationship('author', 'name')
->searchable()

三元过滤器

三元过滤器(TernaryFilter)允许你创建一个拥有三个状态(通常为 true、false 及空白)的 Select 过滤器。要将名为 is_admin 的字段过滤为 truefalse,你可以使用三元过滤器:

use Filament\Tables\Filters\TernaryFilter;

TernaryFilter::make('is_admin')

nullable 字段使用三元过滤器

另一个通用的模式是使用 nullable 字段。比如,使用 email_verified_at 来过滤验证及未验证的用户,未验证的用户在本字段中为空时间戳。要应用该逻辑,你可以使用 nullable() 方法:

use Filament\Tables\Filters\TernaryFilter;

TernaryFilter::make('email_verified_at')
->nullable()

自定义三元过滤器使用的列字段

用于设置查询范围的字段名是过滤器的名称。要自定义字段名,你可以使用 attribute() 方法:

use Filament\Tables\Filters\TernaryFilter;

TernaryFilter::make('verified')
->nullable()
->attribute('status_id')

自定义三元过滤器选项标签

你可以自定义三元过滤器每个状态的标签。true 选项的标签可以使用 trueLabel() 方法自定义。false 选项可以使用 falseLabel() 方法自定义。空白(默认)选项的标签可以使用 placeholder() 方法自定义:

use Illuminate\Database\Eloquent\Builder;
use Filament\Tables\Filters\TernaryFilter;

TernaryFilter::make('email_verified_at')
->label('Email verification')
->nullable()
->placeholder('All users')
->trueLabel('Verified users')
->falseLabel('Not verified users')

自定义三元过滤器修改查询的方式

使用 queries() 方法,你可以自定义三元过滤器的每个状态查询的修改方式:

use Illuminate\Database\Eloquent\Builder;
use Filament\Tables\Filters\TernaryFilter;

TernaryFilter::make('trashed')
->placeholder('Without trashed records')
->trueLabel('With trashed records')
->falseLabel('Only trashed records')
->queries(
true: fn (Builder $query) => $query->withTrashed(),
false: fn (Builder $query) => $query->onlyTrashed(),
blank: fn (Builder $query) => $query->withoutTrashed(),
)

自定义过滤器表单

你可以使用表单构造器的组件,创建自定义过滤器表单。自定义过滤器表单中的数据,可以在 query() 回调中的 $data 数组中获取:

use Filament\Forms\Components\DatePicker;
use Filament\Tables\Filters\Filter;
use Illuminate\Database\Eloquent\Builder;

Filter::make('created_at')
->form([
DatePicker::make('created_from'),
DatePicker::make('created_until'),
])
->query(function (Builder $query, array $data): Builder {
return $query
->when(
$data['created_from'],
fn (Builder $query, $date): Builder => $query->whereDate('created_at', '>=', $date),
)
->when(
$data['created_until'],
fn (Builder $query, $date): Builder => $query->whereDate('created_at', '<=', $date),
);
})
Table with custom filter form

设置自定义过滤器字段的默认值

要在自定义过滤器表单中自定义默认值,你可以使用 default() 方法:

use Filament\Forms\Components\DatePicker;
use Filament\Tables\Filters\Filter;

Filter::make('created_at')
->form([
DatePicker::make('created_from'),
DatePicker::make('created_until')
->default(now()),
])

激活指示器

当过滤器出于激活状态时,在表格内容上面会显示一个指示器,说明表格的查询范围已限定。

Table with filter indicators

默认情况下,过滤器的标签被用作指示器。你可以使用 indicator() 方法对此进行重写:

use Filament\Tables\Filters\Filter;

Filter::make('is_admin')
->label('Administrators only?')
->indicator('Administrators')

自定义激活指示器

并非所有的指示器都很简单,因此您可能需要使用 indicateUsing() 来自定义在哪个时候显示哪个指示器。

例如,如果您有一个自定义日期过滤器,您可以创建一个自定义指示器来格式化所选日期:

use Filament\Forms\Components\DatePicker;
use Filament\Tables\Filters\Filter;

Filter::make('created_at')
->form([DatePicker::make('date')])
// ...
->indicateUsing(function (array $data): ?string {
if (! $data['date']) {
return null;
}

return 'Created at ' . Carbon::parse($data['date'])->toFormattedDateString();
})

多个激活指示器

你甚至可以通过返回 Indicator 对象数组,一次性渲染多个指示器。如果你有关联不同指示器的不同字段,你应该使用字段名作为数组键,以确保过滤器移除时重置的字段正确:

use Filament\Forms\Components\DatePicker;
use Filament\Tables\Filters\Filter;

Filter::make('created_at')
->form([
DatePicker::make('from'),
DatePicker::make('until'),
])
// ...
->indicateUsing(function (array $data): array {
$indicators = [];

if ($data['from'] ?? null) {
$indicators['from'] = 'Created from ' . Carbon::parse($data['from'])->toFormattedDateString();
}

if ($data['until'] ?? null) {
$indicators['until'] = 'Created until ' . Carbon::parse($data['until'])->toFormattedDateString();
}

return $indicators;
})

将过滤器定位到网格列中

要修改过滤器占用的列数,你可以使用 filtersFormColumns() 方法:

use Filament\Tables\Table;

public function table(Table $table): Table
{
return $table
->filters([
// ...
])
->filtersFormColumns(3);
}

控制过滤器下拉菜单的宽度

要自定义下拉菜单的宽度,你可以使用 filtersFormWidth() 方法,并指定一个宽度 - xssmmdlgxl2xl3xl4xl5xl6xl7xl。默认宽度是 xs

use Filament\Tables\Table;

public function table(Table $table): Table
{
return $table
->filters([
// ...
])
->filtersFormWidth('4xl');
}

控制过滤器下拉菜单的最大高度

使用 filtersFormMaxHeight() 方法,并传入一个 CSS 长度,可以为过滤器下拉菜单内容添加最大高度,使之在内容溢出时滚动:

use Filament\Tables\Table;

public function table(Table $table): Table
{
return $table
->filters([
// ...
])
->filtersFormMaxHeight('400px');
}

在表格内容上面显示过滤器

要在表格内容之上渲染过滤器,而非使用下拉菜单,你可以这样使用:

use Filament\Tables\Enums\FiltersLayout;
use Filament\Tables\Table;

public function table(Table $table): Table
{
return $table
->filters([
// ...
], layout: FiltersLayout::AboveContent);
}
Table with filters above content

允许表格内容上面的过滤器折叠

要使内容之上的过滤器折叠,你可以这样使用:

use Filament\Tables\Enums\FiltersLayout;

public function table(Table $table): Table
{
return $table
->filters([
// ...
], layout: FiltersLayout::AboveContentCollapsible);
}

在表格内容下面显示过滤器

要在表格内容之下渲染过滤器,而非使用下拉菜单中渲染,你可以这样使用:

use Filament\Tables\Enums\FiltersLayout;
use Filament\Tables\Table;

public function table(Table $table): Table
{
return $table
->filters([
// ...
], layout: FiltersLayout::BelowContent);
}
Table with filters below content

在 Session 中持久化过滤器

要使用用户 Session 持久化表格过滤器,请使用 persistFiltersInSession() 方法:

use Filament\Tables\Table;

public function table(Table $table): Table
{
return $table
->filters([
// ...
])
->persistFiltersInSession();
}

过滤器改变时取消记录选择

默认情况下,当过滤器改变时,所有记录都会取消选择。使用 deselectAllRecordsWhenFiltered(false) 方法,可以禁用该行为:

use Filament\Tables\Table;

public function table(Table $table): Table
{
return $table
->filters([
// ...
])
->deselectAllRecordsWhenFiltered(false);
}

修改基础查询

默认情况下,对 query() 方法中执行的 Eloquent 查询的修改将会作用于限定查询范围的 where() 语句。这是为了确保该查询不会与任何其他可能应用的过滤器发生冲突,尤其是那些使用 orWhere() 的过滤器。

但是,这样做的缺点是 query() 方法不能使用其他方式修改查询,比如移除全局查询范围,因为需要直接修改的是基础查询,而非限定范围的查询。

要直接修改基础查询,你可以使用 baseQuery() 方法,并传入一个接收该基础查询的闭包:

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Filament\Tables\Filters\TernaryFilter;

TernaryFilter::make('trashed')
// ...
->baseQuery(fn (Builder $query) => $query->withoutGlobalScopes([
SoftDeletingScope::class,
]))

自定义过滤器下来菜单触发 Action

要自定义过滤器下拉触发按钮,你可以使用 filtersTriggerAction() 方法,并传入一个返回 Action 的闭包。自定义 Action 触发按钮中的所有方法都可以用于此处:

use Filament\Tables\Actions\Action;
use Filament\Tables\Table;

public function table(Table $table): Table
{
return $table
->filters([
// ...
])
->filtersTriggerAction(
fn (Action $action) => $action
->button()
->label('Filter'),
);
}
Table with custom filters trigger action

表格过滤器 utility 注入

用于配置过滤器的绝大多数方法都接受函数作为参数,而不是硬编码值:

use App\Models\Author;
use Filament\Tables\Filters\SelectFilter;

SelectFilter::make('author')
->options(fn (): array => Author::query()->pluck('name', 'id')->all())

仅此一点就开启了许多自定义的可能性。

该包也能注入将许多 utilities 作为参数注入到这些函数中。所有接受函数作为参数的自定义方法都可以注入 utilities。

这些注入的 utilities 要求使用特定的参数名。否则,Filament 不清楚注入的是什么。

注入当前过滤器实例

如果你想访问当前过滤器实例,请定义 $filter 参数:

use Filament\Tables\Filters\BaseFilter;

function (BaseFilter $filter) {
// ...
}

注入当前 Livewire 组件实例

如果你想访问表格所属的当前 Livewire 组件实例,请定义 $livewire 参数:

use Filament\Tables\Contracts\HasTable;

function (HasTable $livewire) {
// ...
}

注入当前表格实例

如果你希望访问过滤器所属的当前表格实例,请定义 $table 参数:

use Filament\Tables\Table;

function (Table $table) {
// ...
}

注入多个 utilities

这些参数使用反射动态注入,因此你可以按照任何顺序组合多个参数:

use Filament\Tables\Contracts\HasTable;
use Filament\Tables\Table;

function (HasTable $livewire, Table $table) {
// ...
}

Laravel 容器的注入依赖

你可以像平常那样注入来自 Laravel 容器中的任何东西:

use Filament\Tables\Table;
use Illuminate\Http\Request;

function (Request $request, Table $table) {
// ...
}