news 2026/9/10 14:05:25

Filament TernaryFilter 三元筛选器完全指南:布尔列与可空列的三种状态筛选

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Filament TernaryFilter 三元筛选器完全指南:布尔列与可空列的三种状态筛选

Filament TernaryFilter 三元筛选器完全指南:布尔列与可空列的三种状态筛选

【免费下载链接】filamentA powerful open-source UI framework for Laravel • Build and ship apps & admin panels fast with Livewire项目地址: https://gitcode.com/GitHub_Trending/fi/filament

导读

在 Filament 表格(Table)中,TernaryFilter(三元筛选器)是一个基于SelectFilter内置的选择型筛选组件,它允许用户在一个下拉框里从"真(true)"、"假(false)"与"空白(blank,即不筛选)"三种状态中选择,从而以极简的交互完成对布尔列或可空列的筛选。本文以 TernaryFilter 官方文档 为核心骨架,结合 TernaryFilter.php 源码与 TernaryFilterTest.php 测试用例,完整讲解它的默认行为、nullable()attribute()、标签定制、queries()自定义查询逻辑以及内置的TrashedFilter软删除筛选,帮你写出可直接落地的筛选代码。

认识 TernaryFilter:为什么需要"三种状态"

在 表格筛选器概览文档 中,默认的Filter::make()渲染的是一个复选框,只有"勾选/未勾选"两种状态。而很多业务场景天然是三种状态的:

  • 布尔列(如is_featuredis_published):需要"只看为 true 的""只看为 false 的""全部显示"三个选项;
  • 可空列(如email_verified_at):需要"只看已填值的""只看为 NULL 的""全部显示"三个选项。

TernaryFilter恰好满足这类需求——它把复选框替换成一个Select下拉框,提供三个选项。从源码看,TernaryFilter直接继承自SelectFilter(见 TernaryFilter.php),因此它天然具备 Select 筛选器的全部能力,并在此基础上把"选项"固化为 true / false / blank 三个语义状态。

最小用法

对名为is_featured的布尔列进行 true / false 筛选,只需一行代码:

use Filament\Tables\Filters\TernaryFilter; TernaryFilter::make('is_featured')

在 TernaryFilterTest.php 中可以看到其行为被测试验证:filterTable('is_published', 1)时只显示is_published = true的记录,filterTable('is_published', 0)时只显示is_published = false的记录,而resetTableFilters()后全部记录恢复显示。

默认查询逻辑:boolean()方法

创建TernaryFilter时,其setUp()会自动调用boolean()方法(见 TernaryFilter.php),为三个状态注册默认查询闭包:

状态默认生成的 SQL 条件
truewhere('is_featured', true)
falsewhere('is_featured', false)
blank不添加任何条件

源码实现如下(TernaryFilter.php):

public function boolean(): static { $this->queries( true: fn (Builder $query): Builder => $query->where($this->getAttribute(), true), false: fn (Builder $query): Builder => $query->where($this->getAttribute(), false), ); return $this; }

注意boolean()在查询关系(relationship)时使用whereRelation()处理,这里不再展开,但说明 TernaryFilter 同样兼容关联表列的场景。

用 nullable() 筛选可空列

布尔筛选处理的是"值本身是 true/false"的列;而很多业务列(如email_verified_atdeleted_atcontent)存储的是时间戳或可空值,判断标准是"是否为 NULL"。此时应调用nullable()方法:

use Filament\Tables\Filters\TernaryFilter; TernaryFilter::make('email_verified_at') ->nullable()

nullable()的实现(见 TernaryFilter.php)为三个状态注册如下查询:

状态生成的 SQL 条件
truewhereNotNull('email_verified_at')(已认证用户)
falsewhereNull('email_verified_at')(未认证用户)
blank不添加任何条件(显示全部用户)

测试 TernaryFilterTest.php 中,以content列为对象验证了nullable()行为:filterTable('content', 1)只显示content非空的记录,filterTable('content', 0)只显示content为 NULL 的记录。

用 attribute() 自定义筛选作用的列

TernaryFilter默认使用make()传入的筛选器名称作为查询作用的列名。如果筛选器名称与数据库列名不一致,可以用attribute()指定实际列:

use Filament\Tables\Filters\TernaryFilter; TernaryFilter::make('verified') ->nullable() ->attribute('status_id')

从源码看,attribute()定义在父类SelectFilter中(SelectFilter.php),getAttribute()返回attribute属性的值,若未设置则回退到getName()(SelectFilter.php)。也就是说->attribute('status_id')会把where/whereNull/whereNotNull作用到status_id列上,而上例中nullable()生成的 SQL 即whereNotNull('status_id')/whereNull('status_id')

另外,SelectFilter中的column()方法是attribute()的弃用别名(SelectFilter.php),新代码请统一使用attribute()

定制三种状态的标签与占位符

三个状态的文案默认是英文的"true / false / -"。TernaryFilter提供三个方法定制它们(见 TernaryFilter.php):

  • trueLabel():true 选项的标签;
  • falseLabel():false 选项的标签;
  • placeholder():默认(空白)选项的标签,即下拉框未选择时的占位文案。
use Filament\Tables\Filters\TernaryFilter; TernaryFilter::make('email_verified_at') ->label('Email verification') ->nullable() ->placeholder('All users') ->trueLabel('Verified users') ->falseLabel('Not verified users')

setUp()中的默认值为trueLabel(__('filament-forms::components.select.boolean.true'))falseLabel(__('filament-forms::components.select.boolean.false'))placeholder('-')(见 TernaryFilter.php)。其中trueLabel()falseLabel()均接受字符串或闭包,最终通过getTrueLabel()/getFalseLabel()求值;测试 TernaryFilterTest.php 验证了字符串与闭包两种写法。

当筛选激活时,表格上方的筛选指示条(indicator)会显示"标签: 状态文案",例如"Email verification: Verified users"。该逻辑由setUp()中的indicateUsing()闭包实现(TernaryFilter.php):当状态为空白时返回空数组(不显示指示条),否则根据状态值选用 true/false 标签拼接指示条。

用 queries() 完全掌控查询逻辑

nullable()boolean()只是两个预置方案。当你需要完全自定义三种状态各自的查询时,使用queries()方法,传入三个闭包,分别对应 true、false、blank 状态:

use Illuminate\Database\Eloquent\Builder; use Filament\Tables\Filters\TernaryFilter; TernaryFilter::make('email_verified_at') ->label('Email verification') ->placeholder('All users') ->trueLabel('Verified users') ->falseLabel('Not verified users') ->queries( true: fn (Builder $query) => $query->whereNotNull('email_verified_at'), false: fn (Builder $query) => $query->whereNull('email_verified_at'), blank: fn (Builder $query) => $query, // 本例中 blank 时不希望过滤,直接返回原查询 )

queries() 的底层实现

queries()本身并不直接拼接 SQL,而是把这些闭包组合成query()回调(TernaryFilter.php):

public function queries(Closure $true, Closure $false, ?Closure $blank = null): static { $this->query(function (Builder $query, array $data) use ($blank, $false, $true) { if (blank($data['value'] ?? null)) { return $blank instanceof Closure ? $blank($query, $data) : $query; } return $data['value'] ? $true($query, $data) : $false($query, $data); }); return $this; }

逻辑非常直观:当筛选状态值为空时执行$blank闭包(未提供则原样返回查询);否则按状态值的真假分发到$true$false。因此:

  • blank 闭包是可选的,不传时 blank 状态不做任何筛选;
  • 三个闭包都接收Builder $queryarray $data(包含value键),返回修改后的查询构建器;
  • 状态值1视为 true,0视为 false(getDefaultState()还会把布尔默认值转成整数1/0以匹配 Select 选项值,见 TernaryFilter.php)。

给筛选器设置默认状态

如果你希望表格加载时就默认启用某个状态,可以用default()方法(定义于 HasDefaultState.php):

TernaryFilter::make('is_published') ->default() // 默认显示 true 的记录,等价于 ->default(true)

也支持显式布尔值:->default(true)->default(false)。测试 TernaryFilterTest.php 验证了布尔默认值会被转换为整数1/0,非布尔值(如null)则原样传递。

开箱即用的 TrashedFilter:软删除记录筛选

TrashedFilter是 Filament 内置的一个TernaryFilter子类,专用于筛选软删除记录,直接使用即可:

use Filament\Tables\Filters\TrashedFilter; TrashedFilter::make()

它的名称默认是trashedgetDefaultName()返回'trashed',见 TrashedFilter.php),所以make()可以不带参数。

从 TrashedFilter.php 源码可以看到它的完整配置:

配置项内容
label翻译键filament-tables::table.filters.trashed.label
placeholderwithout_trashed(不含已删除)
trueLabelwith_trashed(含已删除)
falseLabelonly_trashed(仅已删除)
queriestrue →withTrashed(),false →onlyTrashed(),blank →withoutTrashed()
baseQuery移除SoftDeletingScope全局作用域
excludeWhenResolvingRecord解析记录时排除此筛选器

其中两个关键点值得注意:

  1. baseQuery() 移除全局作用域TernaryFilter及所有筛选器的query()回调都作用在加了SoftDeletingScope的查询上,若不先移除该全局作用域,onlyTrashed()等操作无法生效。TrashedFilter通过baseQuery()在基础查询层面移除了SoftDeletingScope(TrashedFilter.php)。baseQuery()方法定义于 InteractsWithTableQuery.php,它允许直接修改基础查询(例如移除全局作用域),而query()只修改受限作用域内的查询——这正是 筛选器概览文档 中 "Modifying the base query" 一节所强调的区别。

  2. excludeWhenResolvingRecord():当用户与表格中的记录交互(如点击行操作)时,Filament 会按当前筛选条件解析记录。TrashedFilter调用了excludeWhenResolvingRecord()(TrashedFilter.php),使该筛选器的query()回调在解析记录时不被应用(但baseQuery()回调仍会应用),从而保证已删除记录的交互不受软删除筛选的阻碍。该方法的通用形式定义于 InteractsWithTableQuery.php。需要强调的是:切勿在承载权限控制的筛选器(如按租户、按用户归属限制记录的筛选器)上使用excludeWhenResolvingRecord(),否则可能造成越权访问。

组合示例:一个完整的用户认证状态筛选

将上述 API 组合起来,一个完整的"邮箱认证状态"筛选器可以写成:

use Illuminate\Database\Eloquent\Builder; use Filament\Tables\Filters\TernaryFilter; use Filament\Tables\Table; public function table(Table $table): Table { return $table ->query(User::query()) ->columns([ Tables\Columns\TextColumn::make('name'), Tables\Columns\TextColumn::make('email'), ]) ->filters([ TernaryFilter::make('verified') ->label('Email verification') ->placeholder('All users') ->trueLabel('Verified users') ->falseLabel('Not verified users') ->nullable() ->attribute('email_verified_at'), ]); }

这里make('verified')只决定筛选器在代码中的唯一标识,attribute('email_verified_at')决定真正筛选的列,nullable()提供基于 NULL 的三态查询,四个 label 类方法完成全部 UI 文案定制。

总结

TernaryFilter用最少的状态模型(true / false / blank)覆盖了布尔列与可空列这两类最常见的筛选诉求:

  • 布尔列直接TernaryFilter::make('is_featured'),由默认的boolean()提供 where true/false 查询;
  • 可空列加->nullable(),自动切换为whereNotNull()/whereNull()
  • 列名与筛选器名不一致时用->attribute('实际列名')
  • 三个状态的文案分别用trueLabel()/falseLabel()/placeholder()定制,并可通过default()预设初始状态;
  • 需要完全自定义时用queries(true: ..., false: ..., blank: ...)接管全部查询逻辑;
  • 软删除场景直接使用内置的TrashedFilter,它借助baseQuery()excludeWhenResolvingRecord()正确隔离全局作用域与记录解析。

需要进一步探索时,可继续阅读 筛选器概览(了解deferFilters()persistFiltersInSession()等表格级配置)、SelectFilter 文档(了解继承自 Select 的searchable()native()等能力),或直接研读 TernaryFilter 源码、TrashedFilter 源码 与 TernaryFilter 测试 加深理解。

【免费下载链接】filamentA powerful open-source UI framework for Laravel • Build and ship apps & admin panels fast with Livewire项目地址: https://gitcode.com/GitHub_Trending/fi/filament

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 14:04:40

深入理解 Rust 中的 Supertrait:以 Trait 组合替代继承的多态实践

深入理解 Rust 中的 Supertrait:以 Trait 组合替代继承的多态实践 【免费下载链接】comprehensive-rust This is the Rust course used by the Android team at Google. It provides you the material to quickly teach Rust. 项目地址: https://gitcode.com/GitH…

作者头像 李华
网站建设 2026/9/10 14:03:55

CANN/ge GetMarks函数

GetMarks 【免费下载链接】ge GE(Graph Engine)是面向昇腾的图编译器和执行器,提供了计算图优化、多流并行、内存复用和模型下沉等技术手段,加速模型执行效率,减少模型内存占用。 GE 提供对 PyTorch、TensorFlow 前端的…

作者头像 李华
网站建设 2026/9/10 14:03:26

MATLAB实现CNN-LSTM融合预测锂电RUL

简介:本资源是一套基于MATLAB实现的锂离子电池剩余使用寿命(RUL)预测项目实战代码,面向新能源、智能运维及AI时序建模方向的研究生、工程师与科研人员,解决传统RUL预测方法精度低、泛化性弱等实际问题。项目创新融合CN…

作者头像 李华
网站建设 2026/9/10 14:03:00

图论基础:图的分类体系与工程应用指南

1. 图论基础与分类体系概述图(Graph)作为离散数学的核心概念之一,在计算机科学、社交网络分析、交通规划等领域有着广泛应用。简单来说,图是由若干顶点(Vertex)和连接这些顶点的边(Edge&#xf…

作者头像 李华
网站建设 2026/9/10 13:59:03

Python代码质量检查工具Pylint与Flake8实战指南

1. 为什么我们需要代码质量检查工具在Python开发中,代码质量直接影响项目的可维护性和团队协作效率。我曾经接手过一个遗留项目,里面充斥着各种命名不规范、未使用的变量和复杂的嵌套逻辑,光是理解代码就花了两周时间。这正是我们需要静态代码…

作者头像 李华