Guides

Seeders

Give each layer its own seeders, order them across layers, and run them from osdd:seed, db:seed or your tests.

An OSDD project has no central DatabaseSeeder to edit: each layer registers its own seeders in its provider, and LayersSeeder runs them all. Adding a layer never touches a shared file.

Register a seeder

A layer registers its seeders in its service provider:

functional/orders/src/Providers/OrdersServiceProvider.php
use Functional\Orders\Database\Seeders\OrdersSeeder;
use Functional\Orders\Database\Seeders\OrderStatusesSeeder;

public function boot(): void
{
    $this->loadSeeders([
        OrderStatusesSeeder::class,
        OrdersSeeder::class,
    ]);
}

osdd:seeder OrdersSeeder --layer=functional/orders creates the seeder and adds the loadSeeders() call for you. A seeder you write by hand needs the call too.

Order seeders across layers

Seeders run by ascending priority, 0 by default. Seeders with the same priority run in registration order. A seeder registered twice runs once, at its first priority.

// Reference data first
$this->loadSeeders([RolesSeeder::class], priority: -10);

// Default priority
$this->loadSeeders([OrdersSeeder::class]);

// Needs the orders
$this->loadSeeders([InvoicesSeeder::class], priority: 10);

Use priorities across layers: the users layer seeds roles at -10, the billing layer seeds invoices at 10, whatever the order Laravel boots their providers in.

How it works

loadSeeders() pushes the classes into the SeederRegistry. osdd:seed runs db:seed --class="Lomkit\Osdd\Seeders\LayersSeeder" once, after --fresh or --refresh. LayersSeeder reads the registry and calls each seeder.

functional/orders/database/seeders/OrdersSeeder.php
<?php

namespace Functional\Orders\Database\Seeders;

use Functional\Orders\Models\Order;
use Illuminate\Database\Seeder;

class OrdersSeeder extends Seeder
{
    public function run(): void
    {
        Order::factory()->count(50)->create();
    }
}

Seed with Laravel's commands and in tests

LayersSeeder also works with Laravel's own seeding:

php artisan db:seed --class="Lomkit\Osdd\Seeders\LayersSeeder"
php artisan migrate:fresh --seed --seeder="Lomkit\Osdd\Seeders\LayersSeeder"
functional/orders/tests/Feature/PlaceOrderTest.php
use Illuminate\Foundation\Testing\RefreshDatabase;
use Lomkit\Osdd\Seeders\LayersSeeder;

class PlaceOrderTest extends TestCase
{
    use RefreshDatabase;

    protected bool $seed = true;

    protected string $seeder = LayersSeeder::class;
}

Pass the full class name: Laravel prefixes a name without a backslash with Database\Seeders\, so --seeder=LayersSeeder is not found.

After osdd:start, LayersSeeder is the default seeder, so php artisan db:seed, migrate --seed, migrate:fresh --seed and RefreshDatabase with only $seed = true run the layer seeders without naming it.

A real Database\Seeders\DatabaseSeeder class, if you write one, takes precedence over the binding: call LayersSeeder from it, as in an existing application.

Run them

php artisan osdd:seed                          # every layer
php artisan osdd:seed --layer=functional/orders  # some layers
php artisan osdd:seed --fresh                  # migrate:fresh first

See osdd:seed for every option and the exit codes.