Как создавать запросы с множественными условиями WHERE в Laravel Eloquent
Вы когда-нибудь ловили себя на мысли: «Мне нужно отфильтровать записи по трём разным условиям, но синтаксис Eloquent какой-то запутанный»? Если да — вы не одиноки. Вопрос "How to Create Multiple Where Clause Query Using Laravel Eloquent?" на Stack Overflow собрал тысячи просмотров, и это неудивительно. Работа с базой данных — сердце любого PHP-приложения, а умение строить сложные запросы отличает новичка от профессионала.
В этой статье мы разберём все способы создания множественных WHERE-условий в Laravel Eloquent: от простейших цепочек до вложенных логических конструкций. Вы узнаете, как комбинировать AND и OR, использовать whereHas для связанных моделей и избегать типичных ошибок. Поехали!
Базовый синтаксис: цепочка WHERE
Самый очевидный способ добавить несколько условий — просто вызвать where() несколько раз подряд. По умолчанию все условия соединяются через AND.
// Получить всех пользователей, у которых status = 'active' И role = 'admin'
$users = User::where('status', 'active')
->where('role', 'admin')
->get();
// Эквивалентный SQL:
// SELECT * FROM users WHERE status = 'active' AND role = 'admin'
Можно передать массив условий:
$users = User::where([
['status', '=', 'active'],
['role', '=', 'admin'],
])->get();
Оба варианта рабочие, но первый читается легче, особенно когда условий становится много.
Условие OR: когда нужно «или»
А что если нам нужно найти пользователей, которые ИЛИ активны, ИЛИ являются администраторами? Тут в игру вступает orWhere().
// Пользователи, у которых status = 'active' ИЛИ role = 'admin'
$users = User::where('status', 'active')
->orWhere('role', 'admin')
->get();
// SQL: SELECT * FROM users WHERE status = 'active' OR role = 'admin'
⚠️ Важное предостережение: Если вы смешиваете where и orWhere, помните о приоритете операторов. Laravel обрабатывает их последовательно, поэтому результат может отличаться от ожидаемого.
Пример с подводным камнем
// Хотим: (status = 'active' AND role = 'admin') OR (plan = 'premium')
$users = User::where('status', 'active')
->where('role', 'admin')
->orWhere('plan', 'premium')
->get();
// SQL: WHERE status = 'active' AND role = 'admin' OR plan = 'premium'
// Это НЕ то же самое!
Чтобы получить правильный результат, используйте группировку с замыканием:
$users = User::where(function ($query) {
$query->where('status', 'active')
->where('role', 'admin');
})->orWhere('plan', 'premium')
->get();
// SQL: WHERE (status = 'active' AND role = 'admin') OR plan = 'premium'
Вложенные WHERE: группировка условий
Когда логика становится сложнее, на помощь приходят вложенные замыкания. Это самый мощный инструмент для создания сложных условий.
// (age > 18 AND status = 'active') OR (age <= 18 AND parent_approved = 1)
$users = User::where(function ($query) {
$query->where('age', '>', 18)
->where('status', 'active');
})->orWhere(function ($query) {
$query->where('age', '<=', 18)
->where('parent_approved', 1);
})->get();
Код читается как книга: «найди пользователей, которые совершеннолетние и активные, ИЛИ несовершеннолетние с одобрением родителей».
Условия с операторами: WHERE IN, BETWEEN, NULL
Eloquent поддерживает все стандартные SQL-операторы. Вот несколько полезных:
whereIn — проверка вхождения в список
$users = User::whereIn('role', ['admin', 'editor', 'moderator'])->get();
// SQL: WHERE role IN ('admin', 'editor', 'moderator')
whereBetween — диапазон значений
$users = User::whereBetween('age', [18, 65])->get();
// SQL: WHERE age BETWEEN 18 AND 65
whereNull / whereNotNull — проверка на NULL
$users = User::whereNull('email_verified_at')->get();
// Все пользователи, не подтвердившие email
Работа со связями: whereHas и whereDoesntHave
Одна из сильнейших сторон Eloquent — фильтрация по связанным моделям. Допустим, у нас есть модель Post, которая belongsTo User. Как найти всех пользователей, у которых есть посты с определённым тегом?
$users = User::whereHas('posts', function ($query) {
$query->where('tags', 'like', '%laravel%')
->where('published', true);
})->get();
А если нужно найти пользователей без постов?
$users = User::whereDoesntHave('posts')->get();
Методы orWhereHas и whereHas отлично комбинируются с обычными условиями:
$users = User::where('status', 'active')
->whereHas('posts', function ($q) {
$q->where('views', '>', 1000);
})
->orWhereHas('comments', function ($q) {
$q->where('created_at', '>', now()->subDay());
})
->get();
Динамические WHERE: whereColumn и whereDate
Иногда нужно сравнить два столбца между собой:
// Найти пользователей, у которых дата создания равна дате обновления
$users = User::whereColumn('created_at', 'updated_at')->get();
// Или с оператором:
$users = User::whereColumn('updated_at', '>', 'created_at')->get();
Для работы с датами есть удобный whereDate:
// Все пользователи, зарегистрированные сегодня
$users = User::whereDate('created_at', today())->get();
// За последнюю неделю
$users = User::whereDate('created_at', '>=', now()->subWeek())->get();
Практический пример: фильтр товаров в интернет-магазине
Давайте соберём всё вместе. Представьте, что вы разрабатываете каталог товаров с фильтрами:
- Категория — обязательный параметр
- Цена — от и до (необязательно)
- Бренды —