Database Seeding
What Is Database Seeding?
Database seeding is the process of automatically filling your database with data.
Instead of manually inserting rows into your tables, Dorguzen allows you to:
- Generate realistic test data
- Populate demo environments
- Prepare development databases
- Recreate consistent test datasets
Think of it like planting seeds 🌱 — your database grows with useful content automatically.
The Seeding Architecture (Simple Overview)
Dorguzen's seeding system has 4 layers:
CLI Command
↓
SeederRunner
↓
Seeder Classes
↓
Factories + Pools
Let's break this down in simple terms.
CLI Commands
Everything starts from the command line.
Basic command
php dgz db:seed
This runs the main seeder class called:
DatabaseSeeder
Run a Specific Seeder
php dgz db:seed --class=UserSeeder
This runs only UserSeeder.
Run All Seeders Explicitly
php dgz db:seed --all
This forces execution of DatabaseSeeder.
Preview Without Running (Pretend Mode)
php dgz db:seed --pretend
This shows what would happen — but does not insert anything.
When the run finishes, Dorguzen confirms with:
Because of your --pretend flag, no queries were ran.
This is safe for testing.
Force Seeding in Protected Environments
php dgz db:seed --force
Some environments (like production) are protected.
--force overrides that safety check.
Fresh Migration + Seed
php dgz migrate:fresh --seed
This:
- Drops all tables
- Re-runs all migrations
- Seeds the database
Perfect for starting over.
Seeder Classes
A Seeder is a class responsible for inserting data into a specific table.
Example:
class UserSeeder extends Seeder
{
protected string $table = 'users';
public function run(): void
{
UserFactory::new()->count(50)->create();
}
}
Simple meaning:
“Create 50 users.”
The Main Seeder: DatabaseSeeder
This is your master orchestrator.
class DatabaseSeeder extends Seeder
{
public function run(): void
{
$this->call(UserSeeder::class);
$this->call(PostSeeder::class);
}
}
This ensures seeders run in the correct order.
Generating a Seeder from the CLI
You don't have to hand-write seeder files. Generate one with:
php dgz make:seeder ProductSeeder
# or hint the table it targets:
php dgz make:seeder ProductSeeder --table=products
This creates database/seeders/ProductSeeder.php, pre-wired with the correct namespace, a $table property, a run() method, and a getTable() method:
namespace Dorguzen\Database\Seeders;
use Dorguzen\Core\Database\Seeders\Seeder;
class ProductSeeder extends Seeder
{
protected string $table = 'products';
public function run(): void
{
$this->factory(ProductFactory::class)
->count(50)
->create($this->table);
}
public function getTable(): string
{
return $this->table;
}
}
If you omit --table, Dorguzen guesses the table name from the seeder name.
Inside a seeder, $this->factory(FactoryClass::class) returns a factory instance, and create() takes the target table name. Every seeder also defines getTable().
Seeding with Raw SQL
Factories are perfect for bulk fake data, but for fixed initial data (settings, a default admin, lookup rows) you can write SQL directly. The Seeder base class exposes the database adapter as $this->db:
public function run(): void
{
$sql = "INSERT IGNORE INTO `categories` (`category_name`, `category_slug`)
VALUES (?, ?)";
$this->db->execute($sql, ['News', 'news']);
$this->db->execute($sql, ['Events', 'events']);
}
Use INSERT IGNORE whenever a unique constraint exists so the seeder is idempotent — safe to run again without creating duplicates. This is exactly how the seeders Dorguzen ships with work.
Factories — Automatic Record Generation
Factories generate rows for your tables.
Example:
class PostFactory extends Factory
{
protected function definition(): array
{
return [
'title' => Pool::get('text.sentence', 6),
'body' => Pool::get('text.paragraph', 4),
'created_at' => Pool::get('date.now'),
'updated_at' => Pool::get('date.now'),
];
}
}
This defines what a “Post” looks like.
When you run:
PostFactory::new()->count(10)->create();
Dorguzen will generate 10 posts automatically.
Data Pools — Smart Fake Data
Pools generate realistic fake data.
Instead of hardcoding text like:
'title' => 'Sample Post'
You can do:
'title' => Pool::get('text.sentence', 6)
And Dorguzen will generate a sentence automatically.
Available Pools
Here are some examples of built-in pools:
Text
Pool::get('text.sentence', 6)
Pool::get('text.paragraph', 3)
Pool::get('text.text', 200)
Names & Emails
Pool::get('name.full')
Pool::get('email', $name)
Numbers
Pool::get('number.int', 1, 100)
Pool::get('number.float', 0, 100, 2)
Pool::get('number.numeric', 6)
Dates
Pool::get('date.now')
Status & Flags
Pool::get('status')
Pool::get('boolean')
This keeps your factories clean and readable.
Factory Lifecycle Hooks
Factories support lifecycle hooks.
beforeCreate()
Modify attributes before inserting:
protected function beforeCreate(array &$attributes): void
{
$attributes['slug'] = strtolower(str_replace(' ', '-', $attributes['title']));
}
afterCreate()
Run logic after insertion:
protected function afterCreate(array $attributes): void
{
// attach relationships
}
Unique Values
Factories support unique generation.
Example:
$email = $this->unique('email', function () use ($name) {
return Pool::get('email', $name);
});
This prevents duplicate values in the database.
Environment Protection
Dorguzen protects important environments.
If seeding is attempted in a protected environment, it will throw an error unless:
--force
This prevents accidental data corruption.
How Everything Works Together
Here is how everything works together. When you run:
php dgz db:seed
Here's what happens internally:
- CLI reads your options
- SeederRunner initializes
- DatabaseSeeder runs
- Individual seeders (your custom seeders in
database/seeders/) execute - Factories (called from your custom seeders) generate records
- Pools (that you use in your factories) generate fake data
- Database is populated
This all happens automatically when you run the seed command:
php dgz db:seed
The Dorguzen seeding system is designed to be:
- Deterministic
- Environment-aware
- CLI-driven
- Extensible
- Cleanly layered
- Dependency-free (no external faker libraries)
It is designed to scale from small hobby projects to Professional applications and even Large systems.
When Should You Use Seeding?
Use seeding when:
- Starting a new development environment
- Resetting a test database
- Preparing demo data
- Running automated tests
- Onboarding new developers
If you remember only three things, let it be these:
- Factories define how a table row looks.
- Seeders decide how many rows to create.
- CLI runs everything.
The SuperAdminSeeder — Your First Login
Dorguzen ships with a SuperAdminSeeder that creates the initial super admin account your application needs from day one. This seeder is registered in DatabaseSeeder and is safe to run at any time — it uses INSERT IGNORE, so running it more than once will never create a duplicate record.
Default super admin credentials
First name : Dorguzen
Last name : Admin
Email : admin@dorguzen.com
Password : Admin123
Use these credentials to log in for the first time. Once you are logged in, go to the admin dashboard and update the super admin's details (name, email, and password) to values specific to your application before going live.
Changing the password can be done from Admin > Manage Users > Edit User (or use the "Admin Change Password" option in the admin dashboard).
Running migrations and the seeder
After setting up your database and running your migrations, run the super admin seeder immediately so the account is available before you open the app in a browser:
# 1. Run all migrations first
php dgz migrate
# 2. Seed the database (creates the super admin account)
php dgz db:seed
Or, if you want to reset everything from scratch:
php dgz migrate:fresh --seed
The seeder is idempotent — it is safe to run it multiple times.
The BaseSettingsSeeder — Default Site Configuration
Alongside SuperAdminSeeder, Dorguzen also registers a BaseSettingsSeeder in DatabaseSeeder. It seeds the baseSettings table with the default site configuration your application reads at runtime — for example the brand-slider toggle and its image source, and the app colour theme. Like the super-admin seeder it uses INSERT IGNORE, so it is safe to re-run:
class BaseSettingsSeeder extends Seeder
{
protected string $table = 'baseSettings';
public function run(): void
{
$sql = "INSERT IGNORE INTO `baseSettings`
(`settings_name`, `settings_value`)
VALUES ('show_brand_slider', 'true'),
('brand_slider_source', 'assets/images/gallery'),
('app_color_theme', '#0d6efd')";
$this->db->execute($sql);
}
public function getTable(): string
{
return $this->table;
}
}