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

Статті за тегом «Чистий код»

Статті, новини, туторіали та переклади від учасників спільноти

No results.
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 21 липня 2026

Accessors & Mutators - автоматична обробка даних

Форматуєте дати у кожному контролері? Перетворюєте імена?

Accessors і Mutators роблять це в моделі.

Accessors - трансформація при читанні Mutators - трансформація при записі

Laravel 9+ синтаксис:

Через клас Attribute.

Переваги:

  • Логіка в одному місці
  • Єдиний формат даних
  • Модель сама відповідає за трансформації

Порада: Ідеально для паролів, форматування дат і тексту.

use Illuminate\Database\Eloquent\Casts\Attribute;

class User extends Model
{
  // Accessor
  protected function name(): Attribute
  {
    return Attribute::make(
      get: fn($value) => ucfirst($value),
    );
  }

  // Mutator
  protected function password(): Attribute
  {
    return Attribute::make(
      set: fn($value) => bcrypt($value),
    );
  }

  // Обидва
  protected function firstName(): Attribute
  {
    return Attribute::make(
      get: fn($value) => ucfirst($value),
      set: fn($value) => strtolower($value),
    );
  }
}
Tips 20 липня 2026

when() - умовні фільтри без if/else

Створюєте фільтр пошуку з купою умов if? Це важко читати.

when() додає умову до запиту тільки тоді, коли вона потрібна.

Переваги:

  • Ланцюжок не переривається
  • Код виглядає чистіше
  • Легко читати
  • Без зайвих тимчасових змінних

Просунутий варіант:

Є callback для "else".

Порада: Ідеально для API-фільтрів, де параметри опціональні.

// ПОГАНО
$query = User::query();
if ($request->status) {
  $query->where('status', $request->status);
}
if ($request->role) {
  $query->where('role', $request->role);
}
$users = $query->get();

// ДОБРЕ
$users = User::query()
  ->when($request->status,
    fn($q, $v) => $q->where('status', $v))
  ->when($request->role,
    fn($q, $v) => $q->where('role', $v))
  ->get();

// З "else"
$users = User::when(
  $request->sort === 'name',
  fn($q) => $q->orderBy('name'),
  fn($q) => $q->orderBy('created_at')
)->get();
Tips 15 липня 2026

Query Scopes - принцип DRY для запитів

Пишете where('status', 'active') у 20 контролерах? Перестаньте дублювати код.

Query Scopes дозволяють повторно використовувати логіку запитів. Описали один раз - застосовуєте всюди.

Два типи:

  • Локальні скоупи - методи в моделі (з параметрами або без).
  • Анонімні скоупи - inline-фільтри без визначення методу.

Чому варто використовувати скоупи:

  1. Повторне використання коду
  2. Краща читабельність
  3. Простота тестування
  4. Легко комбінуються між собою

Порада: Методи локальних скоупів починаються зі слова scope - Laravel автоматично прибирає його.

// User Model
public function scopeActive($query)
{
  return $query->where('status', 'active');
}

public function scopeVerified($query)
{
  return $query->whereNotNull('email_verified_at');
}

public function scopeCreatedAfter($query, $date)
{
  return $query->where('created_at', '>', $date);
}

// Використання - чисто та читабельно
$users = User::active()->verified()->get();

$recentUsers = User::active()
  ->createdAfter(now()->subDays(7))
  ->get();

// Комбінування зі звичайними методами запиту
$admins = User::active()
  ->where('role', 'admin')
  ->orderBy('name')
  ->get();
Tips 28 червня 2026

Dynamic Scopes - побудова складних фільтрів

Побудова фільтрів пошуку з купою if виразів? Код стає нечитабельним.

Dynamic scopes дозволяють чисто ланцюжити умови.

Патерн:

Кожен scope повертає query builder. Ланцюжи декількох scopes разом.

Просунута техніка:

Використовувати when() всередині scopes для опціональних умов.

Переваги:

  • Повторне використання в контролерах
  • Тестування ізольовано
  • Читабельна побудова запитів

Порада: Створи базовий scope на якому можуть будуватися інші scopes.

// Модель User
public function scopeFilter($query, array $filters)
{
    return $query
        ->when($filters['status'] ?? false,
            fn($q, $status) => $q->where('status', $status))
        ->when($filters['role'] ?? false,
            fn($q, $role) => $q->where('role', $role))
        ->when($filters['search'] ?? false,
            fn($q, $search) => $q->where('name', 'like', "%{$search}%"))
        ->when($filters['date_from'] ?? false,
            fn($q, $date) => $q->whereDate('created_at', '>=', $date))
        ->when($filters['date_to'] ?? false,
            fn($q, $date) => $q->whereDate('created_at', '<=', $date));
}

// Контролер - чисто і просто
public function index(Request $request)
{
    return User::filter($request->only([
        'status', 'role', 'search', 'date_from', 'date_to'
    ]))->paginate();
}