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

Subquery Selects - уникаємо N+1 без eager loading

Потрібен останній пост користувача? Eager loading витягне ВСІ пости.

Subquery-select дозволяє додати обчислювану колонку без завантаження зв'язку.

Коли використовувати:

  • Останній/перший пов'язаний запис
  • count/sum/max/min по зв'язку
  • Коли не потрібні повні дані зв'язку

Продуктивність:

Один запит. Ніякого N+1. Немає зайвих даних.

// ПОГАНО: вантажимо всі пости, щоб узяти останній
$users = User::with('posts')->get();
foreach ($users as $user) {
  echo $user->posts
    ->sortByDesc('created_at')->first()->title;
}

// ДОБРЕ: subquery - тільки заголовок останнього поста
$users = User::select('users.*')
  ->addSelect(['last_post_title' => Post::select('title')
    ->whereColumn('user_id', 'users.id')
    ->latest()
    ->limit(1)
  ])->get();

echo $users[0]->last_post_title;

// Сортування по subquery - без завантаження постів
$users = User::orderByDesc(
  Post::select('created_at')
    ->whereColumn('user_id', 'users.id')
    ->latest()
    ->limit(1)
)->get();

Коментарі

Увійдіть, щоб залишити коментар

Будьте першим, хто залишить коментар!

Інші поради

Tips 28 липня 2026

whereHas() проти has() - фільтр за зв'язками

Треба знайти користувачів, у яких є пости? Або тільки з опублікованими постами?

has() перевіряє факт наявності зв'язку. whereHas() дозволяє додати умови до зв'язку.

Різниця:

  • has('posts') - користувачі з будь-якими постами
  • whereHas('posts', fn($q) => ...) - користувачі з конкретними постами

Порада по продуктивності:

Використовуйте has(), коли немає додаткових умов - він простіший.

// Користувачі з будь-якими постами
$users = User::has('posts')->get();

// Користувачі з мінімум 5 постами
$users = User::has('posts', '>=', 5)->get();

// Користувачі тільки з опублікованими постами
$users = User::whereHas('posts', function ($query) {
  $query->where('published', true);
})->get();

// Більш складні умови
$users = User::whereHas('posts', function ($query) {
  $query->where('published', true)
    ->where('views', '>', 1000);
})->get();

// Користувачі без постів
$users = User::doesntHave('posts')->get();

// Комбінування кількох зв'язків
$users = User::has('posts')
  ->whereHas('comments', fn($q) => $q->where('spam', false))
  ->get();
Tips 27 липня 2026

touch() - автооновлення timestamps у батьків

Додали коментар до поста, а updated_at у поста не змінився. Кеш не оновився.

touch() дозволяє автоматично оновлювати час оновлення батьківської моделі.

Як працює:

У дочірній моделі вказуємо $touches. Коли вона зберігається - оновлюється updated_at у батьків.

Де корисно:

  • Інвалідація кешу за timestamp
  • "Остання активність"
  • Відстеження змін контенту

Працює з будь-якими зв'язками.

class Comment extends Model
{
  // Авто-touch для поста
  protected $touches = ['post'];

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

// Тепер при створенні/оновленні коментаря
$comment = new Comment(['body' => 'Great post!']);
$comment->post()->associate($post);
$comment->save();
// updated_at у Post буде оновлено

// Ручне оновлення timestamps
$post->touch();

// Touch кількох зв'язків
class Comment extends Model
{
  protected $touches = ['post', 'author'];
}
Tips 24 липня 2026

whereBelongsTo() - чисті запити по зв'язках

Фільтруєте за зв'язком через where('user_id', $user->id)? Можна краще.

whereBelongsTo() сам підставляє зовнішній ключ.

Переваги:

  • Не треба пам'ятати назву foreign key
  • Працює з кастомним ключем
  • Краще читається
  • Безпечніше при рефакторингу

Бонус: працює з масивом моделей.

Порада: дуже зручно в policy-методах, де фільтруєте по auth()->user().

// ПОГАНО: ручний foreign key
$posts = Post::where('user_id', $user->id)->get();
$comments = Comment::where('post_id', $post->id)->get();

// ДОБРЕ: Laravel сам визначає ключ
$posts = Post::whereBelongsTo($user)->get();
$comments = Comment::whereBelongsTo($post)->get();

// Кілька зв'язків
$comments = Comment::whereBelongsTo($user)
  ->whereBelongsTo($post)
  ->get();

// Кастомна назва зв'язку
$posts = Post::whereBelongsTo($user, 'author')->get();

// У policy - максимально чисто
public function update(User $user, Post $post)
{
  return Post::whereBelongsTo($user)->exists();
}
Tips 23 липня 2026

Події моделей - хуки в життєвий цикл Eloquent

Треба надіслати email після реєстрації? Або залогувати видалення поста?

Model Events дозволяють підключатися до create/update/delete.

Доступні події:

  • creating / created
  • updating / updated
  • deleting / deleted
  • saving / saved

Два підходи:

  • Окремі слухачі (listeners)
  • booted() у моделі (швидкий варіант)

Порада: використовуйте creating для генерації UUID/slug до збереження.

class User extends Model
{
  protected static function booted()
  {
    // Перед створенням
    static::creating(function ($user) {
      $user->uuid = Str::uuid();
    });

    // Після створення
    static::created(function ($user) {
      $user->sendWelcomeEmail();
    });

    // Перед видаленням - каскад
    static::deleting(function ($user) {
      $user->posts()->delete();
    });

    // Повернення false скасовує операцію
    static::creating(function ($user) {
      if ($user->isBanned()) {
        return false;
      }
    });
  }
}
Tips 22 липня 2026

Eloquent Casts - автоматичне перетворення типів

База зберігає JSON як рядок. Ви всюди вручну робите decode.

Casts виконують перетворення типів автоматично. Ви працюєте з нативними типами PHP.

Поширені касти:

  • array / json - авто-encode/decode
  • boolean - 0/1 → true/false
  • date / datetime - об'єкти Carbon
  • encrypted - автоматичне шифрування/дешифрування

Кастомні касти:

Можна створювати власні для складніших перетворень.

Порада: використовуйте encrypted для чутливих даних (напр. номери карток).

class User extends Model
{
  protected $casts = [
    'email_verified_at' => 'datetime',
    'settings' => 'array',
    'is_admin' => 'boolean',
    'metadata' => 'json',
    'birth_date' => 'date',
    'salary' => 'decimal:2',
    'credit_card' => 'encrypted',
  ];
}

// JSON cast - працюємо з масивами
$user->settings = ['theme' => 'dark', 'lang' => 'en'];
$user->save(); // Зберігається як JSON-рядок

$theme = $user->settings['theme']; // Авто-декод

// Datetime cast - Carbon
echo $user->email_verified_at->diffForHumans();

// Boolean cast
if ($user->is_admin) {
  // 1/0 у базі, але в коді - true/false
}
Завантаження...