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

Питання на співбесіді: Seeder

Найпопулярніші питання з реальних Laravel/PHP співбесід для всіх рівнів

3 питання

Seeding - це процес наповнення бази даних початковими або тестовими даними. Laravel робить це через класи-сідери, які лежать у директорії database/seeders. Зручно для довідників (країни, ролі), демо-контенту та локальної розробки чи тестів.

Створити сідер:

php artisan make:seeder PostSeeder

Логіку вставки описують у методі run() - або через фабрики, або напряму через Query Builder:

class PostSeeder extends Seeder
{
    public function run(): void
    {
        Post::factory()->count(50)->create(); // через фабрику

        // або напряму
        DB::table('roles')->insert([
            ['name' => 'admin'],
            ['name' => 'user'],
        ]);
    }
}

Реєстрація: сідери викликають у DatabaseSeeder::run(), щоб запускати їх разом:

public function run(): void
{
    $this->call([RoleSeeder::class, PostSeeder::class]);
}

Запуск:

  • php artisan db:seed - виконує DatabaseSeeder.
  • php artisan db:seed --class=PostSeeder - конкретний сідер.
  • php artisan migrate:fresh --seed - перестворити БД і засіяти.

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

Їх часто плутають, бо обидва створюють записи. Різниця в тому, що саме вони створюють.

Фабрика описує, як виглядає один правдоподібний запис:

class VacancyFactory extends Factory
{
    public function definition(): array
    {
        return [
            'title' => fake()->jobTitle(),
            'level' => fake()->randomElement(VacancyLevel::cases()),
            'is_published' => true,
        ];
    }

    public function draft(): static
    {
        return $this->state(fn () => ['is_published' => false]);
    }
}

Використовується переважно в тестах, де потрібен запис із конкретною властивістю:

$vacancy = Vacancy::factory()->draft()->create();

Сідер заповнює базу набором даних - і зазвичай викликає фабрики:

class DatabaseSeeder extends Seeder
{
    public function run(): void
    {
        $this->call(RolesSeeder::class);       // довідник: конкретні значення
        Vacancy::factory()->count(50)->create(); // демо-дані: випадкові
    }
}

Коли що потрібне:

  • Довідники - ролі, категорії, статуси, налаштування. Це реальні дані застосунку, у них немає випадковості, і вони мають бути ідемпотентними: firstOrCreate() або updateOrCreate(), щоб повторний запуск не плодив дублів.
  • Демо-дані для локальної розробки - фабрики всередині сідера.
  • Тести - фабрики напряму, без сідера: кожен тест створює рівно те, що перевіряє.

Головне правило: сідер із довідником має бути безпечним для повторного запуску, бо його виконують і на проді. Сідер з демо-даними на прод не потрапляє взагалі.

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

Довідники - ролі, статуси, категорії, налаштування - це дані застосунку, а не демо. Вони потрібні на проді, і сідер для них має витримувати повторний запуск.

Не так:

Role::create(['slug' => 'admin', 'name' => 'Адміністратор']);

Другий запуск або впаде на унікальному індексі, або створить дубль.

Так:

foreach ([
    ['slug' => 'admin', 'name' => 'Адміністратор'],
    ['slug' => 'editor', 'name' => 'Редактор'],
] as $role) {
    Role::updateOrCreate(['slug' => $role['slug']], $role);
}

Ключ пошуку - стабільний ідентифікатор, а не id: автоінкремент на різних середовищах різний.

Обережно з updateOrCreate на довідниках, які редагують з адмінки. Він перезапише зміни, зроблені руками. Якщо назву дозволено міняти, оновлювати варто лише технічні поля:

Role::firstOrCreate(['slug' => 'editor'], ['name' => 'Редактор']);

firstOrCreate створює запис, якщо його немає, і не чіпає наявний.

Як запускати на проді:

php artisan db:seed --class=RolesSeeder --force

--force потрібен, бо в продакшн-середовищі Artisan питає підтвердження. Викликати db:seed без --class на проді небезпечно: DatabaseSeeder зазвичай тягне ще й демо-дані.

Альтернатива - зробити це міграцією. Тоді заповнення виконається рівно один раз і саме в потрібний момент деплою, а не за окремою командою, яку легко забути. Для довідника, від якого залежить код нового випуску, це надійніше.

Докладніше в документації: Наповнення бази