split seeders by domain entity

Replaces the laravel-default scaffold seeder with one file per
domain (AdminUser, User, Post, Comment) plus a config/seed.php
to source admin credentials from env. DatabaseSeeder is now a
pure orchestrator that calls the sub-seeders in dependency
order.
This commit is contained in:
Yisroel Baum 2026-05-06 22:38:14 +03:00
parent c55852ec12
commit beb4ddd1e9
Signed by: yisroelbaum
GPG key ID: 0FA60884F75520A9
6 changed files with 213 additions and 9 deletions

View file

@ -0,0 +1,49 @@
<?php
namespace Database\Seeders;
use App\Auth\PasswordHasher;
use App\Shared\ValueObject\EmailAddress;
use App\User\CreateUserDto;
use App\User\User;
use App\User\UserRepository;
use DateTimeImmutable;
use DateTimeZone;
use Illuminate\Database\Seeder;
class AdminUserSeeder extends Seeder
{
public function __construct(
private UserRepository $userRepo,
private PasswordHasher $hasher,
) {}
public function run(): void
{
$email = config('seed.admin.email', 'admin@tide.test');
$displayName = config('seed.admin.display_name', 'admin');
$password = config('seed.admin.password', 'changemenow');
$emailVo = new EmailAddress($email);
if ($this->userRepo->findByEmail($emailVo) !== null) {
return;
}
$now = new DateTimeImmutable('now', new DateTimeZone('UTC'));
$created = $this->userRepo->create(new CreateUserDto(
email: $emailVo,
displayName: $displayName,
passwordHash: $this->hasher->hash($password),
isAdmin: false,
emailConfirmedAt: $now,
));
$this->userRepo->update(new User(
id: $created->getId(),
email: $created->getEmail(),
displayName: $created->getDisplayName(),
passwordHash: $created->getPasswordHash(),
isAdmin: true,
emailConfirmedAt: $now,
));
}
}

View file

@ -0,0 +1,53 @@
<?php
namespace Database\Seeders;
use App\Comment\CommentRepository;
use App\Comment\CreateCommentDto;
use App\Post\PostRepository;
use App\Shared\ValueObject\EmailAddress;
use App\User\UserRepository;
use DateTimeImmutable;
use DateTimeZone;
use Illuminate\Database\Seeder;
class CommentSeeder extends Seeder
{
public function __construct(
private CommentRepository $commentRepo,
private PostRepository $postRepo,
private UserRepository $userRepo,
) {}
public function run(): void
{
$now = new DateTimeImmutable('now', new DateTimeZone('UTC'));
$bob = $this->userRepo->findByEmail(
new EmailAddress('bob@example.com'),
);
$carol = $this->userRepo->findByEmail(
new EmailAddress('carol@example.com'),
);
if ($bob === null || $carol === null) {
return;
}
$posts = $this->postRepo->findRecent(10);
if (count($posts) === 0) {
return;
}
$firstPost = $posts[0];
$this->commentRepo->create(new CreateCommentDto(
postId: $firstPost->getId(),
userId: $bob->getId(),
body: 'Welcome aboard!',
createdAt: $now,
));
$this->commentRepo->create(new CreateCommentDto(
postId: $firstPost->getId(),
userId: $carol->getId(),
body: 'Looking forward to more.',
createdAt: $now->modify('+1 minute'),
));
}
}

View file

@ -2,7 +2,6 @@
namespace Database\Seeders;
use App\Models\User;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
@ -10,16 +9,13 @@ class DatabaseSeeder extends Seeder
{
use WithoutModelEvents;
/**
* Seed the application's database.
*/
public function run(): void
{
// User::factory(10)->create();
User::factory()->create([
'name' => 'Test User',
'email' => 'test@example.com',
$this->call([
AdminUserSeeder::class,
UserSeeder::class,
PostSeeder::class,
CommentSeeder::class,
]);
}
}

View file

@ -0,0 +1,55 @@
<?php
namespace Database\Seeders;
use App\Post\CreatePostDto;
use App\Post\PostRepository;
use App\Shared\ValueObject\EmailAddress;
use App\User\UserRepository;
use DateTimeImmutable;
use DateTimeZone;
use Illuminate\Database\Seeder;
class PostSeeder extends Seeder
{
public function __construct(
private PostRepository $postRepo,
private UserRepository $userRepo,
) {}
public function run(): void
{
$now = new DateTimeImmutable('now', new DateTimeZone('UTC'));
$samples = [
[
'email' => 'alice@example.com',
'title' => 'Hello World',
'body' => 'My first post on TIDE.',
],
[
'email' => 'bob@example.com',
'title' => 'Riding the wave',
'body' => 'Bob shares his thoughts.',
],
[
'email' => 'carol@example.com',
'title' => 'Notes from week one',
'body' => 'Carol lays out her plan.',
],
];
foreach ($samples as $index => $sample) {
$author = $this->userRepo->findByEmail(
new EmailAddress($sample['email']),
);
if ($author === null) {
continue;
}
$this->postRepo->create(new CreatePostDto(
userId: $author->getId(),
title: $sample['title'],
body: $sample['body'],
createdAt: $now->modify("-{$index} hour"),
));
}
}
}

View file

@ -0,0 +1,42 @@
<?php
namespace Database\Seeders;
use App\Auth\PasswordHasher;
use App\Shared\ValueObject\EmailAddress;
use App\User\CreateUserDto;
use App\User\UserRepository;
use DateTimeImmutable;
use DateTimeZone;
use Illuminate\Database\Seeder;
class UserSeeder extends Seeder
{
public function __construct(
private UserRepository $userRepo,
private PasswordHasher $hasher,
) {}
public function run(): void
{
$now = new DateTimeImmutable('now', new DateTimeZone('UTC'));
$samples = [
['email' => 'alice@example.com', 'displayName' => 'alice'],
['email' => 'bob@example.com', 'displayName' => 'bob'],
['email' => 'carol@example.com', 'displayName' => 'carol'],
];
foreach ($samples as $sample) {
$email = new EmailAddress($sample['email']);
if ($this->userRepo->findByEmail($email) !== null) {
continue;
}
$this->userRepo->create(new CreateUserDto(
email: $email,
displayName: $sample['displayName'],
passwordHash: $this->hasher->hash('longenoughpassword'),
isAdmin: false,
emailConfirmedAt: $now,
));
}
}
}