get('DB'), 'users'); } public static function bootstrap(DB\SQL $db): void { if ($db->schema('users', null, 0)) { return; } $db->exec('CREATE TABLE users ( id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT NOT NULL UNIQUE, password_hash TEXT NOT NULL, created_at TEXT NOT NULL )'); } public function findById(int $id): ?array { if ($id <= 0) { return null; } $this->load(['id = ?', $id]); if ($this->dry()) { return null; } $data = $this->cast(); unset($data['password_hash']); // Ne jamais exposer le hash hors de l'authentification. return $data; } public function findByUsername(string $username): ?array { $this->load(['username = ?', $username]); return $this->dry() ? null : $this->cast(); } public function create(string $username, string $password): int { $f3 = Base::instance(); $f3->scrub($username); $username = trim($username); if ($username === '' || $password === '') { throw new RuntimeException('Nom d’utilisateur et mot de passe obligatoires.'); } if (mb_strlen($password) < 10) { throw new RuntimeException('Le mot de passe doit contenir au moins 10 caractères.'); } if ($this->findByUsername($username) !== null) { throw new RuntimeException('Cet utilisateur existe déjà.'); } $this->reset(); $this->username = $username; $this->password_hash = password_hash($password, PASSWORD_DEFAULT); $this->created_at = app_now(); $this->save(); return (int) $this->get('id'); } }