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

Усе про Laravel - в одному місці

Україномовна спільнота розробників: документація Laravel українською, вакансії, статті, події, відео та підготовка до співбесід

Будуй спільноту разом з нами - реєструйся та додавай свій контент

Популярні статті

Найбільш читані матеріали спільноти

Велике оновлення тестів
Рекомендовано
Новини 05 жовтня 2026 28

Велике оновлення тестів і питань для співбесід: 75 тестів, 2791 питання і ваш прогрес

Тести й питання для співбесід на laravelukraine.com ми переробили майже з нуля: 75 тестів у 14 технологіях, 2791 питання з поясненнями, 1740 питань для співбесід у 143 темах. З'явилися підбірки за темами, розбір результату за темами, збереження спроби і сторінка «Моя підготовка», де видно ваш прогрес.

Популярні вакансії

Пропозиції, які найчастіше переглядають

Готуєтесь до співбесіди?

Ми зібрали найпопулярніші питання з реальних співбесід на позиції Laravel розробника для рівнів Junior, Middle та Senior.

1739+ питань · Junior · Middle · Senior Режим флеш-карток для тренування

Laravel Tips & Tricks

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

Tips 05 жовтня 2026

`after()` - хук валідації після проходження всіх правил

Треба перевірити комбінацію полів? Або пов’язані записи в БД?

Звичайні правила працюють незалежно. Хук after() запускається після того, як усі правила пройшли.

Коли корисно:

  • Валідація кількох полів разом
  • Перевірки в БД
  • Складна бізнес-логіка
  • Кастомні повідомлення помилок на основі кількох полів

Суть:

Callback отримує Validator. Помилки додаються вручну.

Порада: after() ідеальний для валідації, що залежить від кількох полів або запитів до БД.

public function withValidator($validator)
{
  $validator->after(function ($v) {
    if ($this->start_date > $this->end_date) {
      $v->errors()->add(
        'end_date',
        'Дата завершення має бути після початку.'
      );
    }

    $total = $this->quantity * $this->price;
    if ($total > 1000 && ! $this->has_approval) {
      $v->errors()->add(
        'has_approval',
        'Замовлення понад $1000 потребують підтвердження.'
      );
    }
  });
}
Tips 02 жовтня 2026

Кастомні правила валідації - коли вбудованих недостатньо

Потрібно перевірити дані через зовнішній API? Або зробити складну перевірку в БД?

Вбудованих правил може не вистачити. Кастомні правила дають повний контроль.

Два підходи:

  • Класи-правила (перевикористовні, тестовані)
  • Closure (швидко, інлайн)

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

  • Бізнес-специфічна валідація
  • Перевірки через зовнішній API
  • Складні запити до БД
  • Перевірки, що залежать від кількох полів

Порада: для правил, які повторюються в різних формах, краще робити окремий клас-правило.

// Швидко: closure-правило
public function rules()
{
  return [
    'username' => [
      'required',
      function ($attr, $value, $fail) {
        if (strtoupper($value) !== $value) {
          $fail("Поле {$attr} має бути у ВЕРХНЬОМУ регістрі.");
        }
      },
    ],
  ];
}

// Перевикористовно: php artisan make:rule Uppercase
class Uppercase implements Rule
{
  public function passes($attribute, $value): bool
  {
    return strtoupper($value) === $value;
  }

  public function message(): string
  {
    return 'Поле :attribute має бути у верхньому регістрі.';
  }
}
Tips 30 вересня 2026

sometimes() - умовні правила валідації

Email обов’язковий… але лише коли тип користувача — customer.

Писати кастомну логіку валідації в контролері? Неохайно.

sometimes() застосовує правила лише тоді, коли умова істинна.

Як це працює:

  • 1-й аргумент — назва поля
  • 2-й аргумент — правила
  • 3-й аргумент — callback-умова

Коли корисно:

  • Поле обов’язкове залежно від іншого поля
  • Різні правила для різних типів користувачів
  • Складна бізнес-логіка у валідації

Порада: складні умови виносьте в окремі методи для читабельності.

$validator = Validator::make($request->all(), [
  'name' => 'required',
  'type' => 'required|in:customer,guest',
]);

$validator->sometimes(
  'email',
  'required|email',
  fn ($input) => $input->type === 'customer'
);

$validator->sometimes(
  ['phone', 'address'],
  'required',
  fn ($input) => $input->type === 'customer'
);

// Складна умова
$validator->sometimes('company_name', 'required', function ($i) {
  return $i->account_type === 'business'
    && $i->annual_revenue > 100000;
});
Tips 28 вересня 2026

diff() і diffKeys() - пошук відмінностей

Порівнюєте колекції? Потрібно знайти, що додалось або зникло?

diff() порівнює значення, diffKeys() - ключі.

Методи:

  • diff() - порівняння за значеннями
  • diffKeys() - за ключами
  • diffAssoc() - за ключем і значенням

Порада: ідеально, щоб визначити, які дані змінилися між двома наборами.

$original = collect([1, 2, 3, 4, 5]);
$updated = collect([1, 2, 3, 6, 7]);

$removed = $original->diff($updated); // [4, 5]
$added   = $updated->diff($original); // [6, 7]

// diffKeys
$old = collect(['a' => 1, 'b' => 2, 'c' => 3]);
$new = collect(['a' => 1, 'b' => 5, 'd' => 4]);

$keyDiff = $old->diffKeys($new);
// ['c' => 3]

// diffAssoc
$assocDiff = $old->diffAssoc($new);
// ['b' => 2, 'c' => 3]

// Виявлення змін у формі
$originalData = collect($user->toArray());
$updatedData  = collect($request->validated());

$changes = $updatedData->diffAssoc($originalData);

if ($changes->isNotEmpty()) {
  $user->update($changes->toArray());
  Log::info('User updated', ['changes' => $changes]);
}
Tips 25 вересня 2026

countBy() - підрахунок за групами

Потрібно порахувати елементи за категоріями?

countBy() групує та одразу рахує.

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

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

Результат:

Колекція, де ключ - група, значення - кількість.

Порада: викликайте з callback, щоб задати власну логіку групування.

$orders = collect([
  ['status' => 'pending'],
  ['status' => 'completed'],
  ['status' => 'pending'],
  ['status' => 'cancelled'],
  ['status' => 'completed'],
  ['status' => 'completed'],
]);

$counts = $orders->countBy('status');
// ['pending' => 2, 'completed' => 3, 'cancelled' => 1]

// Callback
$users = User::all();

$byAge = $users->countBy(fn($u) => floor($u->age / 10) * 10);
// [20 => X, 30 => Y, 40 => Z]

// Email-домени
$emails = collect([
  'john@gmail.com',
  'jane@yahoo.com',
  'bob@gmail.com',
  'alice@gmail.com',
]);

$domains = $emails->countBy(
  fn($e) => explode('@', $e)[1]
);
// ['gmail.com' => 3, 'yahoo.com' => 1]
// Розподіл за довжиною рядка
$words = collect(['hello', 'world', 'php', 'laravel', 'code']);

$lengths = $words->countBy(fn($word) => strlen($word));

// Статистика для dashboard
public function stats()
{
  $orders = Order::whereDate('created_at', today())->get();

  return [
    'by_status' => $orders->countBy('status'),
    'by_payment' => $orders->countBy('payment_method'),
    'by_hour' => $orders->countBy(
      fn($o) => $o->created_at->hour
    ),
  ];
}
Tips 23 вересня 2026

collect() - колекції будь-де

Працюєте з масивами? Перетворіть їх на колекції одним викликом.

collect() обгортає масив у Collection.

Переваги:

  • Fluent-синтаксис
  • Доступ до всіх методів колекцій
  • Використання в будь-яких шарах застосунку

Порада: застосовуйте collect() до масивів з Request для зручного фільтрування.

// Масив → колекція
$data = collect([1, 2, 3, 4, 5]);

$result = $data->filter(fn($n) => $n > 2)
  ->map(fn($n) => $n * 2)
  ->sum();

// Обробка request-даних
public function store(Request $request)
{
  $tags = collect($request->tags)
    ->filter()
    ->unique()
    ->values()
    ->toArray();

  Post::create([
    'title' => $request->title,
    'tags' => $tags,
  ]);
}

// Конфігураційні масиви
$activeModules = collect(config('modules'))
  ->filter(fn($module) => $module['enabled'])
  ->pluck('name')
  ->toArray();
// API-відповідь
$apiData = Http::get('api/users')->json();

$users = collect($apiData['users'])
  ->map(fn($user) => [
    'id' => $user['id'],
    'name' => $user['first_name'] . ' ' . $user['last_name'],
    'email' => $user['email'],
  ])
  ->filter(fn($user) => $user['email'])
  ->values();

// Робота з файлами
$lines = collect(file('data.txt'))
  ->map(fn($line) => trim($line))
  ->filter()
  ->unique();
Tips 21 вересня 2026

zip() і combine() - зшивання колекцій

Маєте два окремі масиви - заголовки й значення? Або назви колонок і рядок CSV?

Зшивати їх циклом по індексу не потрібно.

Різниця:

  • zip() - склеює елементи попарно, повертає колекцію пар
  • combine() - бере першу колекцію як ключі, другу як значення

Де корисно:

  • Парсинг CSV: рядок заголовків + рядки даних
  • Зіставлення результатів двох запитів
  • Побудова асоціативних структур на льоту

Порада: zip() не обрізає до найкоротшої колекції - відсутні значення стають null.

// combine() - ключі + значення
$headers = collect(['name', 'email', 'age']);
$row = ['John', 'john@ex.com', 30];

$user = $headers->combine($row);
// ['name' => 'John', 'email' => 'john@ex.com', 'age' => 30]

// zip() - попарне склеювання
$names = collect(['John', 'Jane']);
$ages = [30, 25];

$pairs = $names->zip($ages);
// [['John', 30], ['Jane', 25]]

// zip() з нерівною довжиною - null у хвості
collect([1, 2, 3])->zip([10, 20]);
// [[1, 10], [2, 20], [3, null]]

// Кілька колекцій одночасно
$names->zip($ages, $emails);
// [['John', 30, 'john@ex.com'], ...]
// Парсинг CSV одним ланцюжком
$lines = collect(file('users.csv'));
$headers = str_getcsv($lines->shift());

$users = $lines->map(fn ($line) =>
  collect($headers)->combine(str_getcsv($line))
);
// $users[0]['email'] - асоціативний доступ

// Зіставлення двох запитів у мапу
$map = Order::pluck('id')
  ->combine(Order::pluck('total'));
// [1 => 250.00, 2 => 130.50]
Tips 18 вересня 2026

skip() і take() - пагінація без БД

Потрібна пагінація на клієнтській стороні або на вже завантажених даних?

skip() і take() працюють як OFFSET і LIMIT.

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

  • In-memory пагінація
  • Розбиття результатів
  • API-слайси

Комбінація:

Використовуються разом.

Порада: forPage() - короткий шлях для skip/take.

$items = collect(range(1, 100));

// Пропустити 20, взяти 10
$page = $items->skip(20)->take(10);
// [21, 22, ..., 30]

// Пагінація вручну
$perPage = 10;
$page = 3;

$results = $items->skip(($page - 1) * $perPage)
  ->take($perPage);

// Коротко: forPage()
$results = $items->forPage(3, 10);

// Умовні варіанти замість числа
$items->skipUntil(fn($i) => $i > 50);
$items->skipWhile(fn($i) => $i < 20);
$items->takeUntil(fn($i) => $i > 50);
$items->takeWhile(fn($i) => $i < 20);
// API-пагінація на закешованих даних
public function index(Request $request)
{
  $all = Cache::remember(
    'products', 3600, fn () => Product::all()
  );

  $page = (int) $request->query('page', 1);
  $perPage = (int) $request->query('per_page', 15);

  return response()->json([
    'data' => $all->forPage($page, $perPage)->values(),
    'current_page' => $page,
    'per_page' => $perPage,
    'total' => $all->count(),
  ]);
}
Tips 16 вересня 2026

sliding() - Створення "ковзних вікон"

Потрібні перекривні чанки? Наприклад, для ковзного середнього?

sliding() створює ковзні вікна по колекції.

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

  • Ковзні середні
  • Аналіз трендів
  • Пошук патернів
  • Послідовний аналіз

Параметри:

  • Розмір вікна
  • Крок (за замовчуванням 1)

Порада: підходить для аналізу часових рядів.

$numbers = collect([1, 2, 3, 4, 5, 6]);

// Розмір 3, крок 1
$windows = $numbers->sliding(3);
// [[1,2,3], [2,3,4], [3,4,5], [4,5,6]]

// Розмір 3, крок 2
$windows = $numbers->sliding(3, 2);
// [[1,2,3], [3,4,5]]

// Ковзне середнє
$values = collect([10, 20, 30, 40, 50]);

$movingAvg = $values->sliding(3)
  ->map(fn($window) => $window->avg());
// [20, 30, 40]
// Аналіз трендів
$prices = collect([100, 105, 103, 110, 115, 112]);

$trends = $prices->sliding(3)
  ->map(fn($w) => [
    'start' => $w->first(),
    'end' => $w->last(),
    'trend' => $w->last() > $w->first() ? 'up' : 'down',
  ]);

// Порівняння сусідніх значень
$changes = $logs->sliding(2)->map(fn($pair) =>
  $pair->last()->value - $pair->first()->value
);

// Пошук послідовностей
$data = collect([1, 2, 3, 5, 6, 7]);

$seq = $data->sliding(2)
  ->filter(fn($p) => $p->last() - $p->first() === 1);
Tips 14 вересня 2026

collapse() - Сплющення вкладених колекцій

Маєте масив масивів? Потрібен один суцільний?

collapse() сплющує лише один рівень.

Приклади використання:

  • Об'єднання кількох колекцій
  • Сплющення згрупованих даних
  • Комбінування результатів запитів

Відмінність від flatten():

  • collapse() - один рівень
  • flatten() - рекурсивно всі рівні

Порада: використовуйте flatten() для глибоко вкладених структур.

// Масив масивів
$data = collect([
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9],
]);

$flat = $data->collapse();
// [1, 2, 3, 4, 5, 6, 7, 8, 9]

// Колекції у колекції
$tags = collect([
  collect(['php', 'laravel']),
  collect(['javascript', 'vue']),
  collect(['mysql', 'redis']),
]);

$allTags = $tags->collapse();
// ['php', 'laravel', 'javascript', 'vue', 'mysql', 'redis']

// Приклад: об'єднання дозволів користувача з ролей
$user->roles->map(fn($role) => $role->permissions)->collapse();

// Групування, а потім collapse
$orders = Order::all()
  ->groupBy('user_id')
  ->map(fn($userOrders) => $userOrders->pluck('items'))
  ->collapse();
// Відмінність collapse vs flatten
$nested = collect([
  [1, [2, [3, 4]]],
  [5, [6, [7, 8]]],
]);

$nested->collapse(); // [1, [2, [3, 4]], 5, [6, [7, 8]]]
$nested->flatten();  // [1, 2, 3, 4, 5, 6, 7, 8]

// Об'єднання масивів із кількох моделей
$allEmails = collect([$users, $admins, $moderators])
  ->map(fn($group) => $group->pluck('email'))
  ->collapse()
  ->unique();

// Теги з постів
$uniqueTags = Post::with('tags')->get()
  ->map(fn($p) => $p->tags)
  ->collapse()
  ->unique('id');

// Комбінування результатів пошуку
$results = collect([$localResults, $apiResults])
  ->collapse()
  ->sortByDesc('relevance');

Популярні відео

Доповіді, які найчастіше переглядають

Вітрина проєктів

Проєкти, створені українською спільнотою на Laravel

Проєкт тижня
Barkme

Barkme

Платформа для моніторингу доступності сайтів і API, стану доменів та SSL-сертифікатів із миттєвими сповіщеннями про збої

Svi-RAG - Інтелектуальний ШІ-консультант

Svi-RAG - Інтелектуальний ШІ-консультант

Інтелектуальний ШІ-консультант для вашого сайту, який автоматизує підтримку клієнтів та генерує ліди 24/7. Сервіс миттєво відповідає на запитання користувачів, використовуючи виключно завантажену вами базу знань (RAG-система на базі Gemini та Postgres pgvector). Якщо клієнту потрібна допомога людини, чат автоматично сповіщає та підключає живого менеджера до діалогу без втрати контексту розмови.

Екосистема Laravel

Пакети та інструменти, які прискорять вашу розробку

Aimeos Laravel

aimeos/aimeos-laravel

Cloud-native, API-first Laravel пакет для електронної комерції з інтегрованою штучною інтелектуальністю для надшвидких онлайн-магазинів, маркетплейсів та складних B2B проектів.

8,707 2026.10.1 13 10

NovaPoshta for Laravel

daaner/novaposhta

Обгортка над API 2.0 Нової Пошти для Laravel: адреси, відділення, вантажі, документи та відстеження посилок. Один із найпоширеніших пакетів для інтеграції з Новою Поштою в українських проєктах.

36 1.4 7 17

Ray

spatie.be/products/ray

Настільний додаток для візуального дебагінгу Laravel та PHP проектів від Spatie.

Tinkerwell

tinkerwell.app

Потужний код-раннер та Tinker-інтерфейс для швидкого запуску PHP коду локально або по SSH.

Перевір свої знання

Пройди інтерактивне тестування та дізнайся свій реальний рівень. Доступні тести для Junior, Middle та Senior розробників.

75 тестів
Junior · Middle · Senior
Публічний результат

Ми в медіа

Публікації про Laravel Ukraine на сторонніх майданчиках

Готові долучитися до спільноти?

Створіть профіль, щоб зберігати статті, відстежувати вакансії та потрапити на карту розробників.