QueryBuilder - фільтр, у якому користувач сам складає умови з груп «І» / «АБО» з необмеженою вкладеністю: «статус - оплачено І (сума > 1000 АБО клієнт - VIP)». Це рівень «розширеного пошуку» CRM, без жодного рядка SQL з боку користувача.
use Filament\QueryBuilder\Constraints\BooleanConstraint;
use Filament\QueryBuilder\Constraints\DateConstraint;
use Filament\QueryBuilder\Constraints\NumberConstraint;
use Filament\QueryBuilder\Constraints\RelationshipConstraint;
use Filament\QueryBuilder\Constraints\RelationshipConstraint\Operators\IsRelatedToOperator;
use Filament\QueryBuilder\Constraints\SelectConstraint;
use Filament\QueryBuilder\Constraints\TextConstraint;
use Filament\Tables\Enums\FiltersLayout;
use Filament\Tables\Filters\QueryBuilder;
->filters([
QueryBuilder::make()
->constraints([
TextConstraint::make('customer_name'),
NumberConstraint::make('total'),
BooleanConstraint::make('is_paid'),
DateConstraint::make('created_at'),
SelectConstraint::make('status')
->options(OrderStatus::class)
->multiple(),
RelationshipConstraint::make('tags')
->multiple()
->selectable(
IsRelatedToOperator::make()
->titleAttribute('name')
->searchable()
->multiple(),
),
NumberConstraint::make('items.qty')->integer(),
]),
], layout: FiltersLayout::AboveContent)
Що дає кожне обмеження: готовий набір операторів для свого типу - «містить», «починається з», «більше», «між датами», «є / немає пов'язаних записів» тощо. Можна перевизначити список операторів і написати власні обмеження й оператори.
Коли QueryBuilder доречний:
- аналітики й менеджери, яким потрібні довільні комбінації умов, а не заздалегідь передбачені фільтри;
- таблиці з десятками полів, де окремий фільтр на кожне перетворив би панель фільтрів на стіну.
Коли краще звичайні фільтри: для 3-5 типових сценаріїв («мої», «неоплачені», «за місяць») звичайні SelectFilter/TernaryFilter зрозуміліші і швидші в роботі.
Що варто врахувати:
- продуктивність. Користувач може зібрати умову, під яку немає жодного індексу:
LIKEпо тексту,ORміж різними колонками,whereHasпо великих зв'язках. На великих таблицях варто обмежити набір обмежень полями з індексами; - зв'язки перетворюються на
whereHas- підзапити, які можуть бути дорогими; - місце. Вкладені групи потребують простору - фільтри краще винести над таблицею (
FiltersLayout::AboveContent); - збереження: у поєднанні з
persistFiltersInSession()складний фільтр не доведеться збирати щоразу.