Skip to content

Seeder ​

Seeders are handled by the roolith/migration package (^2.0) through App\Database\MigrationFactory. Seeder files live in database/seeders as *.seeder.php and applied names are tracked in the shared migrations status table (file_type = 'seeder') so seed data never duplicates between deploys.

Commands ​

Run from the project root:

bash
php roolith seed:create add_users
php roolith seed
php roolith seed:status
php roolith seed:run
php roolith seed:run add_users
  • seed:create <Name> scaffolds database/seeders/<timestamp>_<rand>_<Slug>.seeder.php with a run() skeleton. The directory is created when missing and the name includes a timestamp plus random suffix so concurrent creates never collide. seeder:create is an accepted alias.
  • seed [Name] runs pending seeders in filename order, or one named seeder when given (full timestamped name or short logical name). A failing seeder marks its row failed and the rest still run.
  • seed:run [Name] runs all pending seeders, or one named seeder when given (full timestamped name or short logical name). seeder:run is an accepted alias with the same behavior.
  • seed:status [Name] lists seeder rows with their status. seeder:status is an accepted alias. There is intentionally no seeder rollback; seed data is generally non-reversible.

Seeder files ​

bash
php roolith seed:create add_users
php
<?php

use Roolith\Migration\Interfaces\SeederInterface;
use Roolith\Store\Interfaces\DatabaseInterface;

class _Seeder_20250908120000_ab12_AddUsers implements SeederInterface
{
    /**
     * Run the seeder.
     *
     * @param DatabaseInterface $db Shared database connection.
     * @return void
     */
    public function run(DatabaseInterface $db): void
    {
    }
}

Inside run() you get the database connection, so every driver method from the database page is available on $db.

Complete example ​

Here is a complete seeder file that inserts dummy users into the users table created in the migration example.

php
<?php

use Roolith\Migration\Interfaces\SeederInterface;
use Roolith\Store\Interfaces\DatabaseInterface;

class _Seeder_20250908120000_ab12_UserData implements SeederInterface
{
    public function run(DatabaseInterface $db): void
    {
        $db->execute("
            INSERT INTO users (name, email, role, last_logged_in)
            VALUES
              ('John Doe',                'john.doe@example.com',           'developer', '2025-11-01 09:15:00'),
              ('Bob Smith',               'bob.smith@example.com',          'qa',        '2025-11-02 10:30:00'),
              ('Charlie Nguyen',          'charlie.nguyen@example.com',     'developer', '2025-11-03 11:45:00'),
              ('Diana Patel',             'diana.patel@example.com',        'dba',       '2025-11-04 12:00:00'),
              ('Ethan Clark',             'ethan.clark@example.com',        'developer', '2025-11-05 13:10:00'),
              ('Fatima Ali',              'fatima.ali@example.com',         'qa',        '2025-11-06 14:20:00'),
              ('George Brown',            'george.brown@example.com',       'developer', '2025-11-07 15:35:00'),
              ('Hannah Wilson',           'hannah.wilson@example.com',      'qa',        '2025-11-08 16:40:00'),
              ('Imran Qureshi',           'imran.qureshi@example.com',      'dba',       '2025-11-09 17:55:00'),
              ('Jessica Thompson',        'jessica.thompson@example.com',   'developer', '2025-11-10 18:05:00');
        ");
    }
}

Seeders pair with migrations: migrate the schema first, then seed the rows.

Using Faker for dummy data ​

Install Faker as a dev dependency when you need realistic dummy rows, then use it inside run() the same way as any other $db->table()->insert() call.

bash
composer require --dev fakerphp/faker
php
<?php

use Faker\Factory as FakerFactory;
use Roolith\Migration\Interfaces\SeederInterface;
use Roolith\Store\Interfaces\DatabaseInterface;

class _Seeder_20250908120000_ab12_ProductData implements SeederInterface
{
    public function run(DatabaseInterface $db): void
    {
        $faker = FakerFactory::create();

        for ($i = 0; $i < 10; $i++) {
            $db->table('products')->insert([
                'name' => $faker->words(3, true),
                'price' => $faker->randomFloat(2, 1, 500),
                'stock' => $faker->numberBetween(0, 200),
            ]);
        }
    }
}

Notes ​

  • The shared migrations status table also tracks seeders (file_type = 'seeder'); it is created automatically when missing. The legacy seeds table from the old internal runner is no longer written.
  • Only *.seeder.php files in database/seeders run. Commands accept the full timestamped name or the short logical name; ambiguous short names ask for the full name.
  • Names allow letters, numbers, underscore, and hyphen; paths, .. traversal, and null bytes are rejected before touching the filesystem. A missing file, missing class, or class not implementing SeederInterface fails the row instead of crashing the batch.
  • Class names are generated by the package (_Seeder_<timestamp>_<rand>_<Name>); App\Database\SeederInterface remains as a BC alias.
  • Seeders run via roolith/migration through App\Database\MigrationFactory with php roolith seed, seed:status, seed:create, seed:run (plus seeder:* aliases) commands.

Released under the MIT License.