add user entity

This commit is contained in:
Yisroel Baum 2026-07-31 09:49:18 +03:00
parent b5697e1e1f
commit 0777f0da2f
Signed by: yisroelbaum
GPG key ID: 0FA60884F75520A9
10 changed files with 172 additions and 158 deletions

View file

@ -1,40 +0,0 @@
<?php
namespace App\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Attributes\Hidden;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Carbon;
/**
* @property int $id
* @property string $name
* @property string $email
* @property Carbon|null $email_verified_at
* @property string $password
* @property string|null $remember_token
* @property Carbon|null $created_at
* @property Carbon|null $updated_at
*/
#[Fillable(['name', 'email', 'password'])]
#[Hidden(['password', 'remember_token'])]
class User extends Authenticatable
{
use Notifiable;
/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}
}

View file

@ -2,6 +2,8 @@
namespace App\Providers;
use App\User\EloquentUserRepository;
use App\User\UserRepository;
use Carbon\CarbonImmutable;
use Illuminate\Support\Facades\Date;
use Illuminate\Support\Facades\DB;
@ -15,7 +17,10 @@ class AppServiceProvider extends ServiceProvider
*/
public function register(): void
{
//
$this->app->bind(
UserRepository::class,
EloquentUserRepository::class,
);
}
/**

View file

@ -0,0 +1,40 @@
<?php
namespace App\Shared\ValueObject;
use InvalidArgumentException;
final readonly class EmailAddress
{
private const string ERROR_MESSAGE = 'Invalid email address:';
private string $normalized;
public function __construct(string $email)
{
$trimmedEmail = trim($email);
if (
$trimmedEmail === ''
|| ! str_contains($trimmedEmail, '@')
) {
throw new InvalidArgumentException(
self::ERROR_MESSAGE." $email",
);
}
[$localPart, $domain] = explode('@', $trimmedEmail, 2);
$normalizedEmail = $localPart.'@'.mb_strtolower($domain);
if (filter_var($normalizedEmail, FILTER_VALIDATE_EMAIL) === false) {
throw new InvalidArgumentException(
self::ERROR_MESSAGE." $email",
);
}
$this->normalized = $normalizedEmail;
}
public function value(): string
{
return $this->normalized;
}
}

View file

@ -0,0 +1,12 @@
<?php
namespace App\User;
use App\Shared\ValueObject\EmailAddress;
final readonly class CreateUserDto
{
public function __construct(
public EmailAddress $email,
) {}
}

View file

@ -0,0 +1,35 @@
<?php
namespace App\User;
use App\Shared\ValueObject\EmailAddress;
class EloquentUserRepository implements UserRepository
{
public function create(CreateUserDto $dto): User
{
$model = UserModel::create([
'email' => $dto->email->value(),
]);
return $this->toDomain($model);
}
public function find(int $id): ?User
{
$model = UserModel::find($id);
if ($model === null) {
return null;
}
return $this->toDomain($model);
}
private function toDomain(UserModel $model): User
{
return new User(
id: $model->id,
email: new EmailAddress($model->email),
);
}
}

23
backend/app/User/User.php Normal file
View file

@ -0,0 +1,23 @@
<?php
namespace App\User;
use App\Shared\ValueObject\EmailAddress;
final readonly class User
{
public function __construct(
private int $id,
private EmailAddress $email,
) {}
public function getId(): int
{
return $this->id;
}
public function getEmail(): EmailAddress
{
return $this->email;
}
}

View file

@ -0,0 +1,25 @@
<?php
namespace App\User;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
/**
* @property int $id
* @property string $email
*
* @method static Builder<static>|UserModel newModelQuery()
* @method static Builder<static>|UserModel newQuery()
* @method static Builder<static>|UserModel query()
*
* @mixin \Eloquent
*/
#[Fillable(['email'])]
class UserModel extends Model
{
protected $table = 'users';
public $timestamps = false;
}

View file

@ -0,0 +1,10 @@
<?php
namespace App\User;
interface UserRepository
{
public function create(CreateUserDto $dto): User;
public function find(int $id): ?User;
}

View file

@ -1,117 +0,0 @@
<?php
use App\Models\User;
return [
/*
|--------------------------------------------------------------------------
| Authentication Defaults
|--------------------------------------------------------------------------
|
| This option defines the default authentication "guard" and password
| reset "broker" for your application. You may change these values
| as required, but they're a perfect start for most applications.
|
*/
'defaults' => [
'guard' => env('AUTH_GUARD', 'web'),
'passwords' => env('AUTH_PASSWORD_BROKER', 'users'),
],
/*
|--------------------------------------------------------------------------
| Authentication Guards
|--------------------------------------------------------------------------
|
| Next, you may define every authentication guard for your application.
| Of course, a great default configuration has been defined for you
| which utilizes session storage plus the Eloquent user provider.
|
| All authentication guards have a user provider, which defines how the
| users are actually retrieved out of your database or other storage
| system used by the application. Typically, Eloquent is utilized.
|
| Supported: "session"
|
*/
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
],
/*
|--------------------------------------------------------------------------
| User Providers
|--------------------------------------------------------------------------
|
| All authentication guards have a user provider, which defines how the
| users are actually retrieved out of your database or other storage
| system used by the application. Typically, Eloquent is utilized.
|
| If you have multiple user tables or models you may configure multiple
| providers to represent the model / table. These providers may then
| be assigned to any extra authentication guards you have defined.
|
| Supported: "database", "eloquent"
|
*/
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => env('AUTH_MODEL', User::class),
],
// 'users' => [
// 'driver' => 'database',
// 'table' => 'users',
// ],
],
/*
|--------------------------------------------------------------------------
| Resetting Passwords
|--------------------------------------------------------------------------
|
| These configuration options specify the behavior of Laravel's password
| reset functionality, including the table utilized for token storage
| and the user provider that is invoked to actually retrieve users.
|
| The expiry time is the number of minutes that each reset token will be
| considered valid. This security feature keeps tokens short-lived so
| they have less time to be guessed. You may change this as needed.
|
| The throttle setting is the number of seconds a user must wait before
| generating more password reset tokens. This prevents the user from
| quickly generating a very large amount of password reset tokens.
|
*/
'passwords' => [
'users' => [
'provider' => 'users',
'table' => env('AUTH_PASSWORD_RESET_TOKEN_TABLE', 'password_reset_tokens'),
'expire' => 60,
'throttle' => 60,
],
],
/*
|--------------------------------------------------------------------------
| Password Confirmation Timeout
|--------------------------------------------------------------------------
|
| Here you may define the number of seconds before a password confirmation
| window expires and users are asked to re-enter their password via the
| confirmation screen. By default, the timeout lasts for three hours.
|
*/
'password_timeout' => env('AUTH_PASSWORD_TIMEOUT', 10800),
];

View file

@ -0,0 +1,21 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('users', function (Blueprint $table): void {
$table->id();
$table->string('email')->unique();
});
}
public function down(): void
{
Schema::dropIfExists('users');
}
};