Фильтры
filters() перечисляет фильтры, которые может использовать запрос клиента. У каждого фильтра есть вид, тип значения и набор разрешённых операторов:
public function filters(): array
{
return [
Filter::partial('name'),
Filter::exact('status')->defaultOperator(Operator::In),
Filter::int('views')->operators(),
Filter::datetime('created_at')->operators(Operator::Gte, Operator::Lte),
Filter::enum('role', Role::class),
Filter::scope('popular'),
Filter::trashed(),
];
}Виды
| Фабрика | Сравнение |
|---|---|
Filter::exact('status') | = (in для списка) |
Filter::partial('name'), beginsWith, endsWith | like |
Filter::int, float, bool, date, datetime, enum('status', Status::class) | exact с типизированным значением |
Filter::scope('popular') | скоуп модели, значение — его аргумент (элементы in и границы between — его аргументы) |
Filter::callback('search', fn ($query, $value, Operator $operator) => ...) | ваше замыкание |
Filter::trashed() | with, only или без удалённых моделей |
Типы значений
Тип любого фильтра можно сменить через asInt(), asFloat(), asBool(), asDate(), asDateTime(), asEnum() и asString(). Значение, не подходящее под тип, отклоняется с invalid_value.
- Фильтр
dateсравнивает дату без времени. - Значение
datetimeсо смещением переводится в часовой пояс приложения. - Фильтр
datetimeпринимает и дату без времени и тогда сравнивает по дню в часовом поясе приложения:filter[placed_at]=2026-09-01совпадает со всем днём,[lt]— до него,[lte]— до его конца, а[between]=2026-09-01,2026-09-30берёт оба дня целиком. SQL сравнивает колонку с границами дня, поэтому индекс по ней по-прежнему работает.
Операторы
Операторы указываются в скобках после имени фильтра:
filter[views]=30 equality
filter[views][gte]=20&filter[views][lt]=40
filter[views][between]=20,30 inclusive
filter[views][in]=10,30 also filter[views][in][]=10&filter[views][in][]=30
filter[deleted_at][null]=trueОператоры: eq, ne, gt, gte, lt, lte, in, nin, between и null.
По умолчанию фильтр принимает eq, in (точные небулевы фильтры) и null (nullable-фильтры). ->operators(Operator::Gte, Operator::Lte) разрешает перечисленные, а ->operators() без аргументов — все операторы, подходящие под тип. Операторам сравнения нужен упорядочиваемый тип: число или дата.
Модификаторы
->defaultOperator(Operator::Between): оператор значения, переданного без оператора, так чтоfilter[created_at]=2026-01-01,2026-01-31— диапазон; сOperator::Infilter[status]=new,paid— список (скоуп получает элементы как аргументы, как в spatie). Этот оператор разрешается вместе с остальными, и[eq]по-прежнему означаетeq.->nullable(): пустое значение или[null]=trueсовпадает сNULL, а не игнорируется.->default('published'): значение, когда запрос клиента не упоминает фильтр.->column('created_at'): колонка (или скоуп), если она отличается от имени в запросе.->relation('author.profile'): путь связи, если он отличается от имени.
Фильтрация по связям
Точка в имени фильтрует по связи: Filter::int('posts.views') ограничивает пользователей через whereHas('posts'), а если posts подгружена, сужает и загруженные посты. С ->onlyIncluded() фильтр сужает только подгруженные строки и не трогает корень.
Фильтры по одной связи делят один whereHas: при filter[posts.views][gte]=40&filter[posts.title]=Hello пользователю нужен один пост, подходящий под оба условия, и до таких же постов сужаются подгруженные.
Путь через morphTo требует моделей, на которые он может указывать: Filter::exact('commentable.title')->morphTypes(Post::class, Video::class). Если morphTypes() не задан, берутся типы Relationship::morphTo() на том же пути.
Фильтры вложенных определений
Relationship::to('posts', PostQuery::class)->withFilters() публикует фильтры PostQuery на корне как filter[posts.<name>] (filter[posts.status]=draft). Они работают как любой фильтр по связи; их значения по умолчанию не применяются.