3
+declare(strict_types=1);
6
- * Classe PHP 5 "complète"
7
- * Compatible style PHP 5.x
8
+ * Équivalent conceptuel de la classe PHP 5 ci-dessus,
9
+ * mais avec les apports modernes introduits progressivement
10
+ * entre PHP 7.4 et PHP 8.x.
12
+enum UserStatus: string
14
+ case Pending = 'pending';
15
+ case Active = 'active';
16
+ case Suspended = 'suspended';
19
+final readonly class UserId
21
+ public function __construct(
24
+ if ($this->value <= 0) {
25
+ throw new InvalidArgumentException('L\'identifiant doit être positif.');
30
+final class UserAccount
43
- private $passwordHash;
51
- private $roles = array();
32
+ public function __construct(
33
+ private readonly UserId $id,
34
+ private string $email,
35
+ private string $passwordHash,
36
+ private UserStatus $status = UserStatus::Pending,
37
+ private array $roles = [],
38
+ private readonly DateTimeImmutable $createdAt = new DateTimeImmutable(),
39
+ private ?DateTimeImmutable $updatedAt = null,
41
+ $this->email = self::normalizeEmail($this->email);
43
+ if (!password_get_info($this->passwordHash)['algo']) {
44
+ throw new InvalidArgumentException('Le hash du mot de passe est invalide.');
47
+ $this->roles = array_values(array_unique(array_map('strval', $this->roles)));
60
- public function __construct($id, $email, $plainPassword, array $roles)
62
- $this->id = (int) $id;
63
- $this->setEmail($email);
64
- $this->setPassword($plainPassword);
65
- $this->roles = $roles;
66
- $this->status = 'pending';
67
- $this->createdAt = new DateTime();
68
- $this->updatedAt = null;
49
+ public static function register(
52
+ string $plainPassword,
53
+ array $roles = ['ROLE_USER'],
58
+ passwordHash: password_hash($plainPassword, PASSWORD_DEFAULT),
70
- public function getId()
62
+ public function id(): int
64
+ return $this->id->value;
72
- public function getEmail()
66
+ public function email(): string
73
- public function setPassword($plainPassword)
70
+ public function changePassword(string $plainPassword): void
74
- if (!is_string($plainPassword) || strlen($plainPassword) < 8) {
72
+ if (mb_strlen($plainPassword) < 8) {
73
throw new InvalidArgumentException('Le mot de passe doit contenir au moins 8 caractères.');
75
- $this->passwordHash = sha1($plainPassword);
75
+ $this->passwordHash = password_hash($plainPassword, PASSWORD_DEFAULT);
77
- public function checkPassword($plainPassword)
78
+ public function verifyPassword(string $plainPassword): bool
78
- return $this->passwordHash === sha1($plainPassword);
80
+ return password_verify($plainPassword, $this->passwordHash);
79
- public function getStatus()
82
+ public function status(): UserStatus
80
- return $this->status;
84
+ return $this->status;
81
- public function activate()
86
+ public function activate(): void
82
- if ($this->status === 'active') {
88
+ if ($this->status === UserStatus::Active) {
84
- $this->status = 'active';
91
+ $this->status = UserStatus::Active;
86
- public function suspend()
94
+ public function suspend(): void
87
- $this->status = 'suspended';
96
+ if ($this->status === UserStatus::Suspended) {
99
+ $this->status = UserStatus::Suspended;
89
- public function addRole($role)
102
+ public function addRole(string $role): void
104
+ $role = strtoupper(trim($role));
107
+ throw new InvalidArgumentException('Le rôle ne peut pas être vide.');
110
if (!in_array($role, $this->roles, true)) {
90
- $this->roles[] = $role;
111
+ $this->roles[] = $role;
92
- public function getRoles()
116
+ public function roles(): array
93
- public function getCreatedAt()
120
+ public function createdAt(): DateTimeImmutable
122
return $this->createdAt;
94
- public function getUpdatedAt()
124
+ public function updatedAt(): ?DateTimeImmutable
126
return $this->updatedAt;
95
- public function toArray()
128
+ public function toArray(): array
131
+ 'id' => $this->id(),
132
'email' => $this->email,
98
- 'status' => $this->status,
133
+ 'status' => $this->status->value,
134
'roles' => $this->roles,
99
- 'created_at' => $this->createdAt->format('Y-m-d H:i:s'),
135
+ 'created_at' => $this->createdAt->format(DateTimeInterface::ATOM),
100
- 'updated_at' => $this->updatedAt ? $this->updatedAt->format('Y-m-d H:i:s') : null,
136
+ 'updated_at' => $this->updatedAt?->format(DateTimeInterface::ATOM),
139
+ public function jsonSerialize(): array
141
+ return $this->toArray();
102
- private function touch()
143
+ private function touch(): void
103
- $this->updatedAt = new DateTime();
145
+ $this->updatedAt = new DateTimeImmutable();
147
+ private static function normalizeEmail(string $email): string
149
+ $email = strtolower(trim($email));
151
+ if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
152
+ throw new InvalidArgumentException('Adresse email invalide.');