ulidGenerator->generate($this->clock); ; $now = new \DateTimeImmutable(); $magiclinkData = new MagicLinkData( id: $id, action: $action, payload: MagicLinkPayload::fromArray($payload), expiresAt: $config->getExpiryDateTime(), createdAt: $now, oneTimeUse: $config->oneTimeUse, createdByIp: $createdByIp, userAgent: $userAgent ); $token = new MagicLinkToken($id); $this->tokens[$id] = $magiclinkData; return $token; } public function validate(MagicLinkToken $token): ?MagicLinkData { if (! isset($this->tokens[$token->value])) { return null; } $data = $this->tokens[$token->value]; if (! $data->isValid()) { return null; } return $data; } public function markAsUsed(MagicLinkToken $token): void { if (isset($this->tokens[$token->value])) { $data = $this->tokens[$token->value]; $this->tokens[$token->value] = $data->withUsed(new \DateTimeImmutable()); } } public function revoke(MagicLinkToken $token): void { unset($this->tokens[$token->value]); } public function exists(MagicLinkToken $token): bool { return isset($this->tokens[$token->value]) && $this->tokens[$token->value]->isValid(); } public function getActiveTokens(int $limit = 100): array { return array_slice( array_filter($this->tokens, fn ($data) => $data->isValid()), 0, $limit ); } public function cleanupExpired(): int { $count = 0; foreach ($this->tokens as $id => $data) { if ($data->isExpired()) { unset($this->tokens[$id]); $count++; } } return $count; } }