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

Тарас Сірко

@taras-sirko

Middle Laravel Developer

Редактор Laravel Ukraine. Пишу про релізи, пакети та події спільноти PHP/Laravel.

Київ, Україна
На сайті з 14 червня 2026

Навички

PHP Laravel Livewire Filament
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();
Founders Summit
Новини 24 липня 2026

Laravel оголошує Founders Summit - одноденний захід для засновників

Laravel відкрив прийом заявок на Founders Summit - камерну зустріч для засновників та керівників компаній, що побудовані на Laravel. Захід відбудеться в листопаді 2026 року, а його формат орієнтований на практичний обмін досвідом, а не на доповіді.

Laravel 13.21
Новини 23 липня 2026

Laravel 13.21: атрибут RouteKey для моделей, валідація base64 та розширення можливостей Image

У Laravel 13.21 з'явився атрибут #[RouteKey] для налаштування route model binding, правило валідації base64, атрибут #[RequestAttribute] для впровадження атрибутів запиту, а також підтримка форматів PNG, GIF, AVIF і BMP у компоненті Image.

SMS Catcher
Новини 22 липня 2026

Laravel SMS Catcher: Локальна Панель для Перехоплення SMS-Повідомлень

Laravel SMS Catcher від Michal Skogemann - це інструмент для локальної розробки, що перехоплює вихідні SMS-повідомлення. Подібно до Mailpit для email, він надає візуальну панель для перегляду тексту та метаданих SMS під час локальної роботи.

Laravel Time Machine
Новини 22 липня 2026

Laravel Time Machine: профайлер життєвого циклу запитів

Laravel Time Machine - новий пакет для профілювання продуктивності, що записує кожен етап обробки Laravel-запиту з точністю до мілісекунди. Надає візуальну хронологію від завантаження фреймворку до завершення, зберігає SQL-запити та виділяє повільні операції без використання бази даних.

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),
    );
  }
}
Laravel Installer 5.31.0
Новини 21 липня 2026

Команда `laravel package` для створення пакетів у Laravel Installer v5.31.0

Laravel Installer отримав нову команду для швидкого створення пакетів з CLI, автоматичне визначення версії PHP для GitHub Actions, підтримку --no-node у starter kit хуках та виправлення сумісності для Windows.

AI Review
Новини 10 липня 2026

AI Review для автоматизації оновлень Laravel

Laravel Shift запускає бета-версію AI Review - надбудови, яка виконує другий прохід по оновленню Laravel за допомогою штучного інтелекту. Інструмент аналізує коментарі Shift, розуміє контекст кодової бази та автоматизує додаткові зміни, які зазвичай виконуються вручну розробником.

Intercept
Новини 10 липня 2026

Intercept: Middleware-захист для Laravel AI-агентів

Intercept застосовує знайомий паттерн middleware до промптів, які ваші AI-агенти надсилають провайдерам. Пакет дозволяє перевіряти, переписувати або відхиляти промпти перед відправкою, захищаючи від prompt injection та витоку персональних даних.

HTTP QUERY
Новини 09 липня 2026

Підтримка HTTP-методу QUERY у Laravel 13.19

Laravel 13.19.0 додає повноцінну підтримку HTTP-методу QUERY для клієнта та тестових хелперів, а також покращує роботу з колекціями, рядками та чергами завдань. Серед ключових нововведень - методи Http::query(), reduceInto() та оптимізація масових відправлень у SQS.

Laravel MPP
Новини 08 липня 2026

Laravel MPP: монетизація API для AI-агентів через HTTP 402

Новий пакет Laravel MPP дозволяє розробникам стягувати плату з AI-агентів за доступ до API-маршрутів через стандарт Machine Payments Protocol. Пакет повертає HTTP-відповідь 402 Payment Required та підтримує два платіжні методи: Stripe SPT і Tempo pathUSD.

Tips 04 липня 2026

Оптимізація з Database Views

Складні join'и повторюються скрізь?

Створи database view. Запитуй його як таблицю.

Переваги:

  • Інкапсулює складну логіку
  • Повторне використання в додатку
  • База даних оптимізує view
  • Чистіший код додатку

Компроміс:

Views тільки для читання. Потрібні міграції схеми для змін.

Порада: Ідеально для запитів звітності та дашбордів.

// Створити міграцію для view
public function up()
{
    DB::statement("
        CREATE VIEW user_stats AS
        SELECT
            users.id,
            users.name,
            users.email,
            COUNT(DISTINCT orders.id) as total_orders,
            SUM(orders.total) as total_spent,
            MAX(orders.created_at) as last_order_date
        FROM users
        LEFT JOIN orders ON users.id = orders.user_id
        GROUP BY users.id, users.name, users.email
    ");
}

public function down()
{
    DB::statement("DROP VIEW IF EXISTS user_stats");
}

// Створити модель для view
namespace App\Models;

class UserStats extends Model
{
    protected $table = 'user_stats';
    public $timestamps = false;
    public $incrementing = false;
}
// Використовувати view як звичайну модель
$topCustomers = UserStats::where('total_orders', '>', 10)
    ->orderBy('total_spent', 'desc')
    ->limit(100)
    ->get();

// В контролері
public function dashboard()
{
    $stats = UserStats::where('last_order_date', '>=', now()->subDays(30))
        ->orderBy('total_spent', 'desc')
        ->paginate(50);

    return view('admin.customers', compact('stats'));
}

// Складний view звітності
public function up()
{
    DB::statement("
        CREATE VIEW monthly_revenue AS
        SELECT
            DATE_FORMAT(created_at, '%Y-%m') as month,
            COUNT(*) as order_count,
            SUM(total) as revenue,
            AVG(total) as avg_order_value,
            COUNT(DISTINCT user_id) as unique_customers
        FROM orders
        WHERE status = 'completed'
        GROUP BY DATE_FORMAT(created_at, '%Y-%m')
    ");
}
Clonio CLI
Новини 01 липня 2026

Clonio CLI: Клонування Продакшн-Бази з Анонімізацією Даних

Clonio CLI - інструмент для безпечного копіювання продакшн-бази даних у розробницьке, CI та тестове оточення з автоматичною анонімізацією персональних даних. Підтримує різні стратегії перетворення колонок, ремапінг первинних ключів та виявлення PII.

Tips 30 червня 2026

Lazy Collections з альтернативою cursor()

cursor() тримає з'єднання з БД відкритим. Ризиковано для довгих операцій.

lazy() використовує chunks внутрішньо. Безпечніше.

Як працює lazy():

Завантажує дані пакетами (типово 1000). Видає елементи один за одним. Закриває з'єднання між пакетами.

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

Ефективна пам'ять як cursor(). Безпека з'єднання як chunk(). Найкраще з обох світів.

Порада: Налаштуй розмір chunk з lazy(500) для точного налаштування.

// Ризиковано: З'єднання залишається відкритим
User::cursor()->each(function ($user) {
    // Довга обробка тут може таймаутнути
    $this->sendEmail($user);
});

// Краще: Chunks з lazy ітерацією
User::lazy()->each(function ($user) {
    // Безпечніше для довгих операцій
    $this->sendEmail($user);
});

// Власний розмір chunk
User::lazy(200)->each(function ($user) {
    $this->processUser($user);
});

// Працює з фільтрами
User::where('active', true)
    ->orderBy('created_at')
    ->lazy()
    ->filter(fn($user) => $user->hasOrders())
    ->each(fn($user) => $this->sendPromo($user));
Laravel WhatsApp
Новини 30 червня 2026

Laravel WhatsApp: Два Бекенди За Одним Фасадом

Новий пакет Laravel WhatsApp від Md Mostafijur Rahman дозволяє надсилати та отримувати повідомлення WhatsApp через офіційний Cloud API Meta та неофіційний веб-інтерфейс за допомогою whatsapp-web.js. Обидва варіанти працюють через єдиний фасад WhatsApp::.

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();
}
Privacy Filter
Новини 23 червня 2026

Privacy Filter: виявлення персональних даних у тексті з Laravel

Privacy Filter - Laravel-пакет для автоматичного виявлення персональних даних (імен, email-адрес та іншої конфіденційної інформації) у довільному тексті. Використовує GGML-движок та моделі OpenAI для класифікації токенів через PHP API.

Як Laravel News забезпечив кешування на краю мережі за допомогою Fast Laravel
Новини 18 червня 2026

Як Laravel News забезпечив кешування на краю мережі за допомогою Fast Laravel

Команда Laravel News поділилася досвідом впровадження edge-кешування на високонавантаженому сайті з динамічним контентом. Використовуючи курс Fast Laravel та Cloudflare, вони досягли 70% кешованих запитів і значно пришвидшили роботу сайту.

LaraOwl: self-hosted моніторинг для Laravel-застосунків
Новини 17 червня 2026

LaraOwl: self-hosted моніторинг для Laravel-застосунків

LaraOwl - це open-source платформа моніторингу для Laravel-застосунків, яку ви розгортаєте на власній інфраструктурі. Замість відправлення даних до стороннього сервісу ви встановлюєте LaraOwl-сервер і клієнтський пакет у застосунки, які потрібно відстежувати.

Subscriptionify: пакет для управління підписками на основі функцій у Laravel
Новини 16 червня 2026

Subscriptionify: пакет для управління підписками на основі функцій у Laravel

Subscriptionify - Laravel-пакет для моделювання планів підписки та функцій, які вони відкривають. На відміну від Cashier, залишається незалежним від платіжних шлюзів, відстежуючи плани, квоти та використання у вашій базі даних.

Laravel 13.15.0: типізовані аксесори для перекладів та покращення безпеки
Новини 14 червня 2026

Laravel 13.15.0: типізовані аксесори для перекладів та покращення безпеки

Вийшла версія Laravel 13.15.0 з типізованими методами для перекладів, десеріалізацією JSON Schema, спеціальним драйвером черг для Laravel Cloud та виправленнями вразливостей у валідації та маршрутизації.

Toolkit: каталог готових AI-інструментів для Laravel AI SDK
Новини 14 червня 2026

Toolkit: каталог готових AI-інструментів для Laravel AI SDK

Pushpak Chhajed під егідою Ship Fast Labs представив Toolkit - колекцію готових інструментів для Laravel AI SDK. Кожен інструмент постачається як окремий Composer-пакет без сервіс-провайдерів і спільних залежностей, що дозволяє встановлювати лише потрібні компоненти для ваших AI-агентів.

Tips 04 квітня 2026

cursor() - потокове передавання великих наборів даних

При експорті 100,000 користувачів. get() завантажує все в пам'ять. Сервер падає.

cursor() передає результати один за одним. Константне використання пам'яті.

Як це працює:

Використовує MySQL cursor. Отримує один запис за раз. Пам'ять залишається низькою.

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

  • Експорт великих наборів даних
  • Обробка величезних таблиць
  • Середовища з обмеженою пам'яттю

Компроміс:

Тримає з'єднання з базою даних відкритим довше. Не для веб-запитів, ідеально для команд.

Порада: Використовувати в консольних командах та jobs, уникай в HTTP контролерах.

// ПОГАНО: Завантажує 100k записів в пам'ять
$users = User::all(); // Може впасти
foreach ($users as $user) {
    $this->export($user);
}

// ДОБРЕ: Потокове передавання один за одним
foreach (User::cursor() as $user) {
    $this->export($user); // Константна пам'ять
}

// В консольній команді
public function handle()
{
    $this->output->progressStart(User::count());

    foreach (User::cursor() as $user) {
        $this->processUser($user);
        $this->output->progressAdvance();
    }

    $this->output->progressFinish();
}

// З умовами
foreach (User::where('active', true)->cursor() as $user) {
    // Обробляти тільки активних користувачів
}
Tips 14 березня 2026

Route Caching - миттєвий приріст швидкості

Файл маршрутів завантажується при кожному запиті. З 500+ маршрутами це багато.

Кешування маршрутів компілює маршрути в один закешований файл. В 10 разів швидше.

Як використовувати:

Запустити php artisan route:cache після деплою. Маршрути завантажуються з кешу, а не з файлів.

Важливі обмеження:

Closure маршрути НЕ працюють з кешуванням. Виникнуть помилки. Всі маршрути повинні використовувати синтаксис controller@method.

Найкраща практика:

  1. Ніколи не використовувати closures в маршрутах - завжди контролери
  2. Кешувати маршрути тільки в продакшені
  3. Очищати кеш коли додаються нові маршрути
  4. Додати до скрипту деплою

Порада: Поєднувати з config:cache та view:cache для максимальної продуктивності.

// ПОГАНО: Не працює з route:cache
Route::get('/users', function () {
    return User::all();
});

// ДОБРЕ: Працює з кешуванням
Route::get('/users', [UserController::class, 'index']);

// Команди деплою
php artisan config:cache  // Кешувати конфіг
php artisan route:cache   // Кешувати маршрути
php artisan view:cache    // Кешувати view

// Розробка - очистити всі кеші
php artisan optimize:clear

// Перевірити що маршрути закешовані
php artisan route:list
// Має завантажуватись миттєво якщо закешовано

// В composer.json - авто-кеш після деплою
"scripts": {
    "post-autoload-dump": [
        "@php artisan route:cache"
    ]
}
Tips 06 березня 2026

value() vs first() - економія пам'яті

Потрібна тільки одна колонка з одного рядка? Не треба завантажувати всю модель.

first() створює повну Eloquent модель. value() повертає тільки дані.

Різниця:

  • first() повертає екземпляр моделі з усіма атрибутами
  • value() повертає одне скалярне значення
  • pluck() повертає колекцію значень з кількох рядків

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

Використовувати value() для однієї колонки, одного рядка. Використовувати pluck() для однієї колонки, кількох рядків. Використовувати first() тільки коли потрібні методи моделі.

Порада: На великих таблицях з багатьма колонками value() значно швидший.

// ПОГАНО: Завантажує повну модель з усіма колонками
$email = User::where('id', 1)->first()->email;

// ДОБРЕ: Повертає тільки рядок email
$email = User::where('id', 1)->value('email');

// Декілька рядків, одна колонка
$emails = User::where('active', true)->pluck('email');
// Повертає: Collection ['john@ex.com', 'jane@ex.com']

// Потрібні декілька колонок з кількох рядків?
$users = User::select('id', 'email')->get();

// З ключем за ID
$emails = User::pluck('email', 'id');
// Повертає: [1 => 'john@ex.com', 2 => 'jane@ex.com']