Как создать запрос с несколькими условиями WHERE в Laravel Eloquent?
Основы: цепочка where()
То, что вы написали, абсолютно правильно для простых AND-условий. Laravel Eloquent позволяет вызывать where() несколько раз подряд, и все они будут объединены через AND. Ваш код:
$products = Product::where('status', 'active')
->where('price', '>', 100)
->where('category_id', 5)
->get();
Эквивалентен SQL: WHERE status = 'active' AND price > 100 AND category_id = 5. Это самый распространённый и читаемый способ.
Передача массива условий
Если у вас много условий, можно передать их одним массивом в where():
$conditions = [
['status', '=', 'active'],
['price', '>', 100],
['category_id', '=', 5],
];
$products = Product::where($conditions)->get();
Каждый элемент массива — это [колонка, оператор, значение]. Если оператор не указан, по умолчанию используется '='. Это удобно, когда условия приходят из формы или конфигурации.
Группировка условий (OR и вложенные WHERE)
Для сложной логики (например, (A AND B) OR (C AND D)) используйте замыкания:
$products = Product::where(function ($query) {
$query->where('status', 'active')
->where('price', '>', 100);
})
->orWhere(function ($query) {
$query->where('status', 'pending')
->where('price', '<', 50);
})
->get();
Это даст SQL: WHERE (status = 'active' AND price > 100) OR (status = 'pending' AND price < 50).
Условные where()
Если условие применяется только при определённом значении (например, из запроса), используйте when():
$categoryId = request('category_id'); // может быть null
$minPrice = request('min_price');
$products = Product::when($categoryId, function ($query, $catId) {
return $query->where('category_id', $catId);
})
->when($minPrice, function ($query, $min) {
return $query->where('price', '>=', $min);
})
->get();
Метод when() выполнит замыкание только если первый аргумент истинен. Это избавляет от громоздких if-блоков.
whereIn, whereBetween и другие
Для специфических условий есть специальные методы:
whereIn('category_id', [1, 3, 5])— проверка вхождения в массив.whereBetween('price', [50, 200])— диапазон значений.whereNull('deleted_at')— проверка на NULL.whereDate('created_at', '2023-01-01')— сравнение по дате.
Совет по читаемости
Для длинных запросов разбивайте цепочку на строки и используйте отступы. Если запрос становится слишком сложным, вынесите его в локальные скоупы модели:
class Product extends Model
{
public function scopeActive($query)
{
return $query->where('status', 'active');
}
public function scopeCheaperThan($query, $price)
{
return $query->where('price', '<', $price);
}
}
// Использование:
$products = Product::active()->cheaperThan(200)->get();
Это делает код самодокументируемым и переиспользуемым.
Итог: ваш первый пример корректен. Для простых AND-условий достаточно цепочки where(). Для сложной логики используйте замыкания, when() или скоупы. Массив условий удобен для динамических фильтров.
Альтернатива: использование Query Builder напрямую
Иногда удобнее работать через фасад DB, особенно если запрос не привязан к конкретной модели или требует сложных JOIN:
use Illuminate\Support\Facades\DB;
$products = DB::table('products')
->where('status', 'active')
->where(function ($query) {
$query->where('price', '>', 100)
->orWhere('discount', '>', 0);
})
->whereIn('category_id', [1, 3, 5])
->get();
Это даёт SQL: WHERE status = 'active' AND (price > 100 OR discount > 0) AND category_id IN (1,3,5).
Динамические условия через when() с массивом
Если у вас много фильтров из формы, можно комбинировать when() с массивом условий для большей гибкости:
$filters = [
'status' => request('status'),
'min_price' => request('min_price'),
'max_price' => request('max_price'),
];
$products = Product::query()
->when($filters['status'], fn($q, $v) => $q->where('status', $v))
->when($filters['min_price'], fn($q, $v) => $q->where('price', '>=', $v))
->when($filters['max_price'], fn($q, $v) => $q->where('price', '<=', $v))
->get();
Этот подход особенно полезен для API с фильтрацией, так как позволяет легко добавлять или убирать условия без изменения структуры запроса.
Ответов пока нет.
Войдите чтобы оставить ответ