
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_featured、is_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.phppublic 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_at、deleted_at、content存储的是时间戳或可空值判断标准是是否为 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.phpgetAttribute()返回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.phptrueLabel()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.phppublic 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 $query与array $data包含value键返回修改后的查询构建器状态值1视为 true0视为 falsegetDefaultState()还会把布尔默认值转成整数1/0以匹配 Select 选项值见 TernaryFilter.php。给筛选器设置默认状态如果你希望表格加载时就默认启用某个状态可以用default()方法定义于 HasDefaultState.phpTernaryFilter::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.labelplaceholderwithout_trashed不含已删除trueLabelwith_trashed含已删除falseLabelonly_trashed仅已删除queriestrue →withTrashed()false →onlyTrashed()blank →withoutTrashed()baseQuery移除SoftDeletingScope全局作用域excludeWhenResolvingRecord解析记录时排除此筛选器其中两个关键点值得注意baseQuery() 移除全局作用域TernaryFilter及所有筛选器的query()回调都作用在加了SoftDeletingScope的查询上若不先移除该全局作用域onlyTrashed()等操作无法生效。TrashedFilter通过baseQuery()在基础查询层面移除了SoftDeletingScopeTrashedFilter.php。baseQuery()方法定义于 InteractsWithTableQuery.php它允许直接修改基础查询例如移除全局作用域而query()只修改受限作用域内的查询——这正是 筛选器概览文档 中 Modifying the base query 一节所强调的区别。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),仅供参考