Ensuring exclusive role filters with Spatie in Laravel

Hello everyone, I’m encountering an issue with my role-based filters in Laravel (using Spatie for role management). Right now, when I select multiple roles—such as super_admin and doctor—the query returns any record that has either role. In other words, I see: - Users with only the super_admin role - Users with only the doctor role - Users who have both roles What I want instead is an exclusive filter. If I select super_admin and doctor, I should only see users who have both of those roles simultaneously. Below is the relevant code snippet I’m using to apply these filters. Any guidance on how to make the role filter “AND” instead of “OR” would be greatly appreciated:
->filters([
SelectFilter::make('roles')
->multiple()
->preload()
->relationship('roles', 'name')
])
->filters([
SelectFilter::make('roles')
->multiple()
->preload()
->relationship('roles', 'name')
])
No description
Solution:
Check the apply() method of the SelectFilter. When using multiple in uses whereIn(). You can create or own Filter, extend the SelectFilter and overwrite the apply method to your liking. Lines 166–182...
Jump to solution
2 Replies
Solution
Dennis Koch
Dennis Koch4mo ago
Check the apply() method of the SelectFilter. When using multiple in uses whereIn(). You can create or own Filter, extend the SelectFilter and overwrite the apply method to your liking. Lines 166–182
Laird Fire
Laird FireOP4mo ago
Thank you, it's working fine now. Here is the exclusive filter in case anyone would need it :
<?php

namespace App\Filament\Filters;

use Filament\Tables\Filters\SelectFilter;
use Illuminate\Database\Eloquent\Builder;

class ExactRolesSelectFilter extends SelectFilter
{
public function apply(Builder $query, array $data = []): Builder
{
$isMultiple = $this->isMultiple();
$values = $isMultiple
? $data['values'] ?? []
: [$data['value'] ?? null];

$values = array_filter((array) $values, fn($v) => filled($v));

if (empty($values)) {
return $query;
}

return $query
->whereHas('roles', function ($q) use ($values) {
$q->whereIn('roles.id', $values);
}, '=', count($values))
->whereDoesntHave('roles', function ($q) use ($values) {
$q->whereNotIn('roles.id', $values);
});
}
}
<?php

namespace App\Filament\Filters;

use Filament\Tables\Filters\SelectFilter;
use Illuminate\Database\Eloquent\Builder;

class ExactRolesSelectFilter extends SelectFilter
{
public function apply(Builder $query, array $data = []): Builder
{
$isMultiple = $this->isMultiple();
$values = $isMultiple
? $data['values'] ?? []
: [$data['value'] ?? null];

$values = array_filter((array) $values, fn($v) => filled($v));

if (empty($values)) {
return $query;
}

return $query
->whereHas('roles', function ($q) use ($values) {
$q->whereIn('roles.id', $values);
}, '=', count($values))
->whereDoesntHave('roles', function ($q) use ($values) {
$q->whereNotIn('roles.id', $values);
});
}
}

Did you find this page helpful?