← Назад к вопросам

Как сформировать запрос в Laravel на уровне моделей?

1.3 Junior🔥 201 комментариев
#Базы данных и SQL#Фреймворки

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Формирование запросов в Laravel на уровне моделей: комплексный подход

В Laravel Eloquent ORM предоставляет несколько элегантных способов формирования запросов непосредственно через модели. Основной принцип — работа с объектами и отношениями, а не с сырыми SQL-запросами.

Основные методы построения запросов

1. Прямое использование Query Builder через модель

// Получение экземпляра Query Builder
$users = User::where('active', true)
             ->orderBy('name')
             ->take(10)
             ->get();

2. Scope-методы для повторяющихся условий

Локальные scopes в модели:

class User extends Model
{
    public function scopeActive($query)
    {
        return $query->where('active', true);
    }
    
    public function scopeOfType($query, $type)
    {
        return $query->where('type', $type);
    }
}

// Использование
$activeUsers = User::active()->get();
$adminUsers = User::active()->ofType('admin')->get();

Продвинутые техники работы с моделями

Eager Loading для решения проблемы N+1

// Проблема: N+1 запрос при доступе к отношениям
$posts = Post::all();
foreach ($posts as $post) {
    echo $post->author->name; // Отдельный запрос для каждого поста
}

// Решение: Eager Loading
$posts = Post::with(['author', 'comments.user'])->get();

Использование отношений как конструкторов запросов

class User extends Model
{
    public function posts()
    {
        return $this->hasMany(Post::class);
    }
}

// Работа с отношениями как с Query Builder
$recentPosts = $user->posts()
                   ->where('published', true)
                   ->whereDate('created_at', '>', now()->subDays(7))
                   ->orderBy('views', 'desc')
                   ->get();

Глобальные scopes для принудительных условий

class ActiveScope implements Scope
{
    public function apply(Builder $builder, Model $model)
    {
        $builder->where('active', true);
    }
}

class User extends Model
{
    protected static function booted()
    {
        static::addGlobalScope(new ActiveScope);
    }
    
    // Отключение глобального scope
    public static function withoutGlobalScopeActive()
    {
        return static::withoutGlobalScope(ActiveScope::class);
    }
}

// Все запросы автоматически получат условие WHERE active = true
$users = User::all(); // Уже с фильтром по активным

Оптимизация производительности

  1. Выбор конкретных полей:
// Избегаем SELECT *
$users = User::select('id', 'name', 'email')->get();
  1. Chunking для больших наборов данных:
User::where('active', true)->chunk(200, function ($users) {
    foreach ($users as $user) {
        // Обработка
    }
});
  1. Lazy Eager Loading:
$posts = Post::all();
$posts->load('comments'); // Подгрузка отношений после получения основной модели

Кастомные запросы через raw выражения

// Безопасное использование raw выражений
$users = User::selectRaw('COUNT(*) as total, role')
             ->groupBy('role')
             ->havingRaw('COUNT(*) > 1')
             ->get();

Лучшие практики и рекомендации

  • Инкапсуляция логики: Помещайте сложные условия запросов в scope-методы или отдельные классы-построители запросов
  • Тестируемость: Query Builder легко мокать и тестировать
  • Безопасность: Eloquent автоматически экранирует параметры, предотвращая SQL-инъекции
  • Читаемость: Цепочки методов создают самодокументируемый код
  • Гибкость: Можно комбинировать с Query Builder, когда нужны особые оптимизации

Ключевое преимущество работы на уровне моделей — соблюдение принципов SOLID, особенно принципа единственной ответственности, когда модель отвечает не только за данные, но и за логику доступа к ним.

Как сформировать запрос в Laravel на уровне моделей? | PrepBro