Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Laravel: Eloquent під навантаженням

20 питань · ~20 хв · Версія v3.0

Увійдіть, щоб продовжити

Великі таблиці й мільйони рядків: підзапити замість циклів, масові оновлення й очищення, обхід без браку пам'яті, агрегати, повнотекстовий пошук, діагностика запитів - питання від middle до lead.

За спробу
20
У пулі
43
Проходжень
0
Середній бал
-
Пройшли на 70%+
-

Питання для підготовки

52 питання

Eloquent - це ORM (object-relational mapping) Laravel, реалізація патерну Active Record. Кожній таблиці відповідає модель (зазвичай у app/Models), рядок таблиці - це екземпляр моделі, а робота з даними виглядає як робота зі звичайними PHP-об'єктами замість написання SQL.

Створити модель (за конвенцією однина: Post → таблиця posts):

php artisan make:model Post -mf   # одразу з міграцією та фабрикою

Базові операції (CRUD):

$post = Post::create(['title' => 'Привіт']); // create
$post = Post::find(1);                       // read
$post->update(['title' => 'Оновлено']);      // update
$post->delete();                             // delete

Post::where('is_published', true)->latest()->get();

Що дає Eloquent понад Query Builder:

  • Зв'язки - hasOne, hasMany, belongsTo, belongsToMany, поліморфні.
  • Аксесори/мутатори та касти атрибутів (наприклад, дати, enum, JSON).
  • Події моделі та обзервери (creating, saved, deleted).
  • Scopes для перевикористання умов запитів.

Eloquent побудований поверх Query Builder, тож ті самі методи (where, orderBy, join) доступні і на моделях.

Докладніше в документації: Eloquent ORM

N+1 виникає, коли ви завантажуєте N моделей одним запитом, а потім у циклі звертаєтесь до їхнього зв'язку - це генерує ще N запитів.

$posts = Post::all(); // 1 запит
foreach ($posts as $post) {
    echo $post->author->name; // +1 запит на кожен пост → N запитів
}

Рішення - eager loading через with():

$posts = Post::with('author')->get(); // лише 2 запити загалом

Вкладені та умовні зв'язки:

Post::with(['author', 'comments.user'])->get();        // вкладений eager
Post::with(['comments' => fn ($q) => $q->latest()])->get(); // умовний

Лічильники без завантаження зв'язку - withCount() (без N+1 і без вантаження самих рядків):

$posts = Post::withCount('comments')->get(); // доступ через $post->comments_count

Виявлення: Model::preventLazyLoading(! app()->isProduction()) у boot() кидає виняток на ледачих завантаженнях поза продакшеном; також допомагають Telescope і Debugbar.

Докладніше в документації: Eloquent: Eager Loading

Обидва методи виконують запит, але повертають різне:

  • get() повертає колекцію (Illuminate\Database\Eloquent\Collection) усіх відповідних моделей. Якщо нічого не знайдено - порожню колекцію, а не null. Підходить, коли треба перебрати кілька записів.
  • first() повертає одну першу модель або null, якщо нічого не знайдено. Підходить, коли очікуєш один запис.
$posts = Post::where('active', true)->get();   // Collection (0..N моделей)
$post  = Post::where('slug', $slug)->first();  // Post|null

foreach ($posts as $post) { /* ... */ }        // get() - ітеруємо
echo $post?->title;                            // first() - перевіряємо на null

Споріднені методи:

  • find($id) - пошук за первинним ключем.
  • firstOrFail() / findOrFail() - як first()/find(), але кидають ModelNotFoundException (HTTP 404), якщо запис відсутній.
  • pluck('email') - колекція значень одного стовпця.
  • value('email') - одне скалярне значення з першого рядка.

Підсумок: get() - багато рядків (колекція), first() - один рядок (модель або null).

Докладніше в документації: Eloquent: отримання моделей

Eloquent підтримує всі поширені типи зв'язків між таблицями, кожен оголошується методом на моделі:

  • One To One - hasOne / belongsTo. Приклад: User ↔ Profile.
  • One To Many - hasMany / belongsTo. Приклад: Post → багато Comment.
  • Many To Many - belongsToMany через проміжну (pivot) таблицю. Приклад: User ↔ Role.
  • Has One/Many Through - доступ до віддаленого зв'язку через проміжну модель.
  • Polymorphic - morphTo / morphMany: модель належить кільком типам (наприклад, Comment може належати і Post, і Video).

Оголошення зв'язку:

class Post extends Model
{
    public function comments(): HasMany
    {
        return $this->hasMany(Comment::class);
    }
}

class Comment extends Model
{
    public function post(): BelongsTo
    {
        return $this->belongsTo(Post::class);
    }
}

Використання:

$post->comments;               // колекція коментарів
$comment->post->title;         // зворотний бік
Post::with('comments')->get(); // eager loading проти N+1

Завжди завантажуйте потрібні зв'язки через with(), щоб уникнути проблеми N+1.

Докладніше в документації: Зв’язки Eloquent

Mass Assignment - це присвоєння групи атрибутів моделі з масиву (наприклад, Model::create($request->all())). Вразливість виникає, коли користувач підкидає неочікувані поля (скажімо, is_admin).

Захист - білий або чорний список у моделі:

protected $fillable = ['title', 'body']; // дозволено лише ці
// або
protected $guarded = ['id', 'is_admin']; // заборонено ці

Найкраща практика: не передавати $request->all(), а валідувати й передавати $request->validated().

Докладніше в документації: Mass Assignment

Прочитати - ще не значить знати

20 питань, по одному на екран, ~20 хв. Після завершення - розбір кожної помилки з посиланням на питання.