Фильтрация и сортировка
Фильтры через query-параметры
$query = Post::query();
if ($request->filled('search')) {
$query->where('title', 'like', "%{$request->search}%");
}
if ($request->filled('status')) {
$query->where('status', $request->status);
}
if ($request->filled('user_id')) {
$query->where('user_id', $request->user_id);
}
return PostResource::collection($query->paginate(15));
Метод when
Чище, чем if:
$query = Post::query()
->when($request->filled('search'), fn ($q) => $q->where('title', 'like', "%{$request->search}%"))
->when($request->filled('status'), fn ($q) => $q->where('status', $request->status))
->when($request->filled('user_id'), fn ($q) => $q->where('user_id', $request->user_id));
Сортировка с белым списком
Никогда не передавай имя колонки напрямую из запроса — это SQL-инъекция:
$sort = $request->get('sort', 'created_at');
$direction = $request->get('direction', 'desc');
$allowed = ['title', 'created_at', 'views', 'published_at'];
if (!in_array($sort, $allowed)) {
$sort = 'created_at';
}
$direction = in_array($direction, ['asc', 'desc']) ? $direction : 'desc';
$posts = Post::orderBy($sort, $direction)->paginate(15);
Множественная сортировка
$posts = Post::orderBy('published_at', 'desc')
->orderBy('title', 'asc')
->paginate(15);
Фильтр по диапазону дат
$query->when($request->filled('from'), fn ($q) => $q->where('created_at', '>=', $request->from))
->when($request->filled('to'), fn ($q) => $q->where('created_at', '<=', $request->to));
Фильтр по массиву
$query->when($request->filled('ids'), fn ($q) => $q->whereIn('id', $request->ids));
Связи с фильтром
$query->whereHas('comments', function ($q) use ($request) {
$q->where('approved', true);
});
Query Object
Если фильтров много — их выносят в отдельный класс:
namespace App\Queries;
use Illuminate\Http\Request;
use Illuminate\Database\Eloquent\Builder;
class PostFilter
{
public function __construct(private Request $request) {}
public function apply(Builder $query): Builder
{
return $query
->when($this->request->filled('search'), fn ($q) => $q->where('title', 'like', "%{$this->request->search}%"))
->when($this->request->filled('status'), fn ($q) => $q->where('status', $this->request->status));
}
}
Использование:
$query = (new PostFilter($request))->apply(Post::query());