Как составить сложный WHERE в Laravel Eloquent: 4 способа с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Как составить сложный WHERE в Laravel Eloquent: 4 способа с примерами

Представьте: вы пишете интернет-магазин на Laravel. Нужно найти все товары, которые стоят от 1000 до 5000 рублей, в наличии, но не из категории "Распродажа", и при этом созданы после 1 января 2024 года. Как это сделать одним запросом, не убивая производительность?

Этот вопрос — один из самых популярных на Stack Overflow (тысячи просмотров!). И не зря: умение строить сложные условия WHERE в Laravel Eloquent отличает новичка от продакшен-разработчика.

В этой статье я покажу 4 проверенных способа создавать множественные условия WHERE. Вы узнаете, когда использовать массивы, а когда — замыкания, как группировать условия и как не допустить SQL-инъекций. Поехали!


1. Базовый способ: массив условий (для простых AND)

Самый простой случай — когда все условия соединяются через AND. Laravel позволяет передать в where() обычный массив:

<?php

// Хотим найти активных пользователей из России, созданных в 2024 году
$users = User::where([
    ['status', '=', 'active'],
    ['country', '=', 'Russia'],
    ['created_at', '>=', '2024-01-01'],
])->get();

// SQL: SELECT * FROM users WHERE status = 'active' AND country = 'Russia' AND created_at >= '2024-01-01'

Когда использовать: когда у вас 2-5 простых условий с оператором = или >. Код получается читаемым, но не гибким.

Минус: если нужно смешивать AND и OR, массив не подойдёт.

2. Цепочка методов where() (для динамических условий)

Это самый популярный способ среди разработчиков. Вы просто вызываете where() несколько раз подряд:

<?php

$products = Product::where('price', '>', 1000)
    ->where('price', '<', 5000)
    ->where('in_stock', true)
    ->where('category_id', '!=', 5)
    ->get();

// SQL: ... WHERE price > 1000 AND price < 5000 AND in_stock = 1 AND category_id <> 5

Хитрость: вы можете комбинировать с другими условиями:

<?php

// Условие "ИЛИ" внутри цепочки
$orders = Order::where('status', 'paid')
    ->orWhere('status', 'shipped')
    ->where('total', '>', 100)  // Внимание: это условие применяется к предыдущему orWhere!
    ->get();

// SQL: ... WHERE status = 'paid' OR (status = 'shipped' AND total > 100)

⚠️ Важно! В последнем примере где total > 100 применяется только к status = 'shipped'. Если вам нужно, чтобы оба статуса были с total > 100 — читайте следующий пункт.

3. Группировка условий через замыкания (AND + OR вместе)

Здесь мы подходим к самому мощному инструменту. Когда нужно создать группу условий в скобках — используйте замыкание (closure) внутри where():

<?php

// Задача: найти заказы со статусом "paid" или "shipped", 
// но при этом total должен быть > 100 в обоих случаях
$orders = Order::where(function($query) {
        $query->where('status', 'paid')
              ->orWhere('status', 'shipped');
    })
    ->where('total', '>', 100)
    ->get();

// SQL: ... WHERE (status = 'paid' OR status = 'shipped') AND total > 100

Теперь условия сгруппированы правильно! Вы можете вкладывать замыкания друг в друга сколько угодно раз:

<?php

// Сложный фильтр для аналитики
$data = Sale::where('date', '>=', '2024-01-01')
    ->where(function($q) {
        $q->where('amount', '>', 10000)
          ->orWhere('is_vip', true);
    })
    ->where(function($q) {
        $q->where('region', 'Europe')
          ->orWhere('region', 'Asia');
    })
    ->get();

// SQL: ... WHERE date >= '2024-01-01' 
//   AND (amount > 10000 OR is_vip = 1) 
//   AND (region = 'Europe' OR region = 'Asia')

Жизненный пример: представьте, что вы делаете фильтр товаров на сайте. Пользователь выбрал: цена от 1000 до 5000, бренд Nike или Adidas, скидка не менее 20%. Вот как это будет выглядеть:

<?php

$filteredProducts = Product::whereBetween('price', [1000, 5000])
    ->where(function($q) {
        $q->where('brand', 'Nike')
          ->orWhere('brand', 'Adidas');
    })
    ->where('discount', '>=', 20)
    ->orderBy('price')
    ->paginate(20);

4. Специализированные where-методы (whereIn, whereNull, whereHas)

Laravel даёт множество удобных сокращений. Вот самые полезные:

whereIn — когда нужно проверить множество значений

<?php

// Вместо цепочки orWhere
$users = User::whereIn('role', ['admin', 'editor', 'moderator'])->get();
// SQL: ... WHERE role IN ('admin', 'editor', 'moderator')

whereBetween — диапазон значений

<?php

$events = Event::whereBetween('event_date', ['2024-06-01', '2024-06-30'])->get();

whereNull / whereNotNull — проверка на NULL

<?php

// Найти пользователей, которые не подтвердили email
$unverified = User::whereNull('email_verified_at')->get();

// Найти товары с заполненным описанием
$withDescription = Product::whereNotNull('description')->get();

whereHas — условия по связанным моделям

Это отдельная магия Eloquent. Допустим, у нас есть модель Post с отношением comments(). Хотим найти посты, у которых есть хотя бы 5 комментариев от активных пользователей:

<?php

$popularPosts = Post::whereHas('comments', function($query) {
    $query->where('status', 'approved')
          ->whereHas('user', function($q) {
              $q->where('is_active', true);
          });
}, '>                

Блоги

Рекомендаций по книгам