em->wrapInTransaction(function () use ($apiKeyMeta) { $apiKey = ApiKey::fromMeta($this->ensureUniqueName($apiKeyMeta)); $this->em->persist($apiKey); return $apiKey; }); } /** * Given an ApiKeyMeta object, it returns another instance ensuring the name is unique. * - If the name was auto-generated, it continues re-trying until a unique name is resolved. * - If the name was explicitly provided, it throws in case of name conflict. */ private function ensureUniqueName(ApiKeyMeta $apiKeyMeta): ApiKeyMeta { if (! $this->repo->nameExists($apiKeyMeta->name)) { return $apiKeyMeta; } if (! $apiKeyMeta->isNameAutoGenerated) { throw new InvalidArgumentException( sprintf('Another API key with name "%s" already exists', $apiKeyMeta->name), ); } return $this->ensureUniqueName(ApiKeyMeta::fromParams( expirationDate: $apiKeyMeta->expirationDate, roleDefinitions: $apiKeyMeta->roleDefinitions, )); } public function createInitial(string $key): ApiKey|null { return $this->repo->createInitialApiKey($key); } public function check(string $key): ApiKeyCheckResult { $apiKey = $this->findByKey($key); return new ApiKeyCheckResult($apiKey); } /** * @inheritDoc */ public function deleteByName(string $apiKeyName): void { $affectedResults = $this->repo->deleteByName($apiKeyName); if ($affectedResults === 0) { throw ApiKeyNotFoundException::forName($apiKeyName); } } /** * @inheritDoc */ public function disableByName(string $apiKeyName): ApiKey { $apiKey = $this->repo->findOneBy(['name' => $apiKeyName]); if ($apiKey === null) { throw ApiKeyNotFoundException::forName($apiKeyName); } return $this->disableApiKey($apiKey); } /** * @inheritDoc */ public function disableByKey(string $key): ApiKey { $apiKey = $this->findByKey($key); if ($apiKey === null) { throw ApiKeyNotFoundException::forKey($key); } return $this->disableApiKey($apiKey); } private function disableApiKey(ApiKey $apiKey): ApiKey { $apiKey->disable(); $this->em->flush(); return $apiKey; } /** * @return ApiKey[] */ public function listKeys(bool $enabledOnly = false): array { $conditions = $enabledOnly ? ['enabled' => true] : []; return $this->repo->findBy($conditions); } /** * @inheritDoc */ public function renameApiKey(Renaming $apiKeyRenaming): ApiKey { $apiKey = $this->repo->findOneBy(['name' => $apiKeyRenaming->oldName]); if ($apiKey === null) { throw ApiKeyNotFoundException::forName($apiKeyRenaming->oldName); } if (! $apiKeyRenaming->nameChanged()) { return $apiKey; } $this->em->wrapInTransaction(function () use ($apiKeyRenaming, $apiKey): void { if ($this->repo->nameExists($apiKeyRenaming->newName)) { throw ApiKeyConflictException::forName($apiKeyRenaming->newName); } $apiKey->name = $apiKeyRenaming->newName; }); return $apiKey; } private function findByKey(string $key): ApiKey|null { return $this->repo->findOneBy(['key' => ApiKey::hashKey($key)]); } }