Whenever you have an orWhere, you always need to wrap that query in a function. It ensures that the query gets wrapped in ()
$query->when($filters['search'] ?? null, function ($query, $search) use ($filters) {
$query->where(function ($q) { //here
$q->where('name', 'like', "%{$search}%")
->orWhere('first_name', 'like', "%{$search}%")
->orWhere('last_name', 'like', "%{$search}%")
->orWhere('email', 'like', "%{$search}%");
});
})->when($filters['sortColumn'] ?? null, function ($query, $sortColumn) use ($filters) {
$query->orderBy($sortColumn, $filters['sortDirection']);
})->when($filters['option'] ?? null, function ($query, $option) {
$query->whereHas('roles', function ($query) use ($option) {
$query->where('role_id', '=', $option);
});
});