How to Make Multiple Select Filters Combine with 'And' Logic Instead of 'Or' Logic in FilamentPHP?

When I select multiple options from a single Select Filter, it treats them as an orWhere, which is expected. However, when I select options simultaneously from two or more Select Filters, it also treats them as orWhere. However, I need them to be treated as andWhere. How can I achieve this behavior? Here are two examples of the filters:
SelectFilter::make('type_id')
->label('Type')
->query(function (Builder $query, array $data): Builder {
$values = $data['values'];
foreach ($values as $value) {
$query = $query->orWhere('types.type_id', $value);
}
return $query;
})
->options(Type::all()->pluck('type_name', 'type_id'))
->multiple(),
SelectFilter::make('category_id')
->label('Category')
->query(function (Builder $query, array $data): Builder {
$values = $data['values'];

foreach ($values as $value) {
$query->orWhere('categories.category_id', $value);
}

return $query;
})
->options(Category::all()->pluck('category_name', 'category_id'))
->multiple();
SelectFilter::make('type_id')
->label('Type')
->query(function (Builder $query, array $data): Builder {
$values = $data['values'];
foreach ($values as $value) {
$query = $query->orWhere('types.type_id', $value);
}
return $query;
})
->options(Type::all()->pluck('type_name', 'type_id'))
->multiple(),
SelectFilter::make('category_id')
->label('Category')
->query(function (Builder $query, array $data): Builder {
$values = $data['values'];

foreach ($values as $value) {
$query->orWhere('categories.category_id', $value);
}

return $query;
})
->options(Category::all()->pluck('category_name', 'category_id'))
->multiple();
1 Reply
rominronin
rominronin3mo ago
This is an old post, but I'm in v3 and I'm trying to do something similar. I've achieved it using custom select filters, which are then updating a component property $this->filter_value, which is then being checked in $table->modifyQueryUsing. This works, but I'm wondering if there is a neater way to implement this. ah, just found a better way to do this: ->baseQuery
SelectFilter::make('dim_width')
->baseQuery(fn(Builder $query, $state) => $state['value'] ? $query->where('dim_width', '=', $state['value']) : $query)
->options(function () {
$query = $this->getTableQuery();
return $query->orderBy('dim_width')->distinct('dim_width')->pluck('dim_width', 'dim_width')->toArray();
}),
SelectFilter::make('dim_width')
->baseQuery(fn(Builder $query, $state) => $state['value'] ? $query->where('dim_width', '=', $state['value']) : $query)
->options(function () {
$query = $this->getTableQuery();
return $query->orderBy('dim_width')->distinct('dim_width')->pluck('dim_width', 'dim_width')->toArray();
}),
This is cool, but if you you Filter (instead of SelectFilter), you can use ->form() to have more control over the form and it's reactivity.