← Назад к вопросам
Как сформировать запрос в 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(); // Уже с фильтром по активным
Оптимизация производительности
- Выбор конкретных полей:
// Избегаем SELECT *
$users = User::select('id', 'name', 'email')->get();
- Chunking для больших наборов данных:
User::where('active', true)->chunk(200, function ($users) {
foreach ($users as $user) {
// Обработка
}
});
- 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, особенно принципа единственной ответственности, когда модель отвечает не только за данные, но и за логику доступа к ним.