diff --git a/backend/app/User/EloquentUserRepository.php b/backend/app/User/EloquentUserRepository.php new file mode 100644 index 0000000..f5887ea --- /dev/null +++ b/backend/app/User/EloquentUserRepository.php @@ -0,0 +1,43 @@ + $dto->email->value(), + 'password_hash' => $dto->passwordHash, + 'is_admin' => $dto->isAdmin, + ]); + + return $this->toDomain($model); + } + + public function find(int $id): ?User + { + $model = UserModel::find($id); + + return $model === null ? null : $this->toDomain($model); + } + + public function findByEmail(EmailAddress $email): ?User + { + $model = UserModel::where('email', $email->value())->first(); + + return $model === null ? null : $this->toDomain($model); + } + + private function toDomain(UserModel $model): User + { + return new User( + id: $model->id, + email: new EmailAddress($model->email), + passwordHash: $model->password_hash, + isAdmin: $model->is_admin, + ); + } +} diff --git a/backend/app/User/UserModel.php b/backend/app/User/UserModel.php new file mode 100644 index 0000000..767ac29 --- /dev/null +++ b/backend/app/User/UserModel.php @@ -0,0 +1,38 @@ +|UserModel newModelQuery() + * @method static Builder|UserModel newQuery() + * @method static Builder|UserModel query() + * @method static Builder|UserModel whereId($value) + * @method static Builder|UserModel whereEmail($value) + * @method static Builder|UserModel whereIsAdmin($value) + * + * @mixin \Eloquent + */ +class UserModel extends Model +{ + protected $table = 'users'; + + public $timestamps = false; + + protected $fillable = [ + 'email', + 'password_hash', + 'is_admin', + ]; + + protected $casts = [ + 'is_admin' => 'boolean', + ]; +} diff --git a/backend/composer.json b/backend/composer.json index 93db624..abe76eb 100644 --- a/backend/composer.json +++ b/backend/composer.json @@ -49,7 +49,7 @@ "npx concurrently -c \"#93c5fd,#c4b5fd,#fb7185\" \"php artisan serve\" \"php artisan queue:listen --tries=1\" \"php artisan pail --timeout=0\" --names=server,queue,logs --kill-others" ], - "stan": "phpstan analyse", + "stan": "phpstan analyse --no-progress", "cs:fix": "php-cs-fixer fix", "cs:check": "php-cs-fixer check --diff -vvv", diff --git a/backend/database/migrations/2026_05_06_000000_create_users_table.php b/backend/database/migrations/2026_05_06_000000_create_users_table.php new file mode 100644 index 0000000..45e4086 --- /dev/null +++ b/backend/database/migrations/2026_05_06_000000_create_users_table.php @@ -0,0 +1,23 @@ +id(); + $table->string('email')->unique(); + $table->string('password_hash'); + $table->boolean('is_admin')->default(false); + }); + } + + public function down(): void + { + Schema::dropIfExists('users'); + } +}; diff --git a/backend/tests/Fakes/FakeUserRepository.php b/backend/tests/Fakes/FakeUserRepository.php new file mode 100644 index 0000000..3ad23bd --- /dev/null +++ b/backend/tests/Fakes/FakeUserRepository.php @@ -0,0 +1,66 @@ +getNextId(); + $user = new User( + id: $id, + email: $dto->email, + passwordHash: $dto->passwordHash, + isAdmin: $dto->isAdmin, + ); + $this->existingUsers[$id] = $user; + + return $user; + } + + public function find(int $id): ?User + { + $user = $this->existingUsers[$id] ?? null; + if ($user === null) { + return null; + } + + return new User( + id: $user->getId(), + email: $user->getEmail(), + passwordHash: $user->getPasswordHash(), + isAdmin: $user->isAdmin(), + ); + } + + public function findByEmail(EmailAddress $email): ?User + { + foreach ($this->existingUsers as $user) { + if ($user->getEmail()->equals($email)) { + return new User( + id: $user->getId(), + email: $user->getEmail(), + passwordHash: $user->getPasswordHash(), + isAdmin: $user->isAdmin(), + ); + } + } + + return null; + } + + private function getNextId(): int + { + return count($this->existingUsers) + 1; + } +}