feat: lots more improvements

Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
2026-04-25 15:43:56 -04:00
parent 6ab61301dc
commit 7485e4c897
9 changed files with 403 additions and 125 deletions

View File

@@ -26,45 +26,39 @@ class ServiceStore
public function __construct(
protected readonly DataStore $dataStore,
protected readonly Crypto $crypto,
protected readonly Crypto $crypto,
) {}
// ── List ─────────────────────────────────────────────────────────────────
/**
* List services for a tenant+user, optionally filtered to specific IDs.
*
* @param string[]|null $filter Service IDs to restrict results to
* @return array<string, array> Keyed by service ID
* List services for a tenant and user, optionally filtered by service IDs
*/
public function list(string $tenantId, string $userId, ?array $filter = null): array
{
$condition = ['tid' => $tenantId, 'uid' => $userId];
$filterCondition = [
'tid' => $tenantId,
'uid' => $userId,
];
if ($filter !== null && !empty($filter)) {
$condition['sid'] = ['$in' => $filter];
$filterCondition['sid'] = ['$in' => $filter];
}
$cursor = $this->dataStore->selectCollection(self::COLLECTION_NAME)->find($condition);
$cursor = $this->dataStore->selectCollection(self::COLLECTION_NAME)->find($filterCondition);
$list = [];
foreach ($cursor as $entry) {
if (isset($entry['identity']['secret'])) {
$entry['identity']['secret'] = $this->crypto->decrypt($entry['identity']['secret']);
}
$list[$entry['sid']] = $entry;
}
return $list;
}
// ── Extant ───────────────────────────────────────────────────────────────
/**
* Check which of the supplied service IDs exist for the given tenant/user.
*
* @param string[]|int[] $identifiers
* @return array<string, bool>
* Check existence of services by IDs for a tenant and user
*/
public function extant(string $tenantId, string $userId, array $identifiers): array
{
@@ -76,27 +70,29 @@ class ServiceStore
[
'tid' => $tenantId,
'uid' => $userId,
'sid' => ['$in' => array_map('strval', $identifiers)],
'sid' => ['$in' => array_map('strval', $identifiers)]
],
['projection' => ['sid' => 1]],
['projection' => ['sid' => 1]]
);
$existing = [];
foreach ($cursor as $doc) {
$existing[] = $doc['sid'];
$existingIds = [];
foreach ($cursor as $document) {
$existingIds[] = $document['sid'];
}
// Build result map: all identifiers default to false, existing ones set to true
$result = [];
foreach ($identifiers as $id) {
$result[(string)$id] = in_array((string)$id, $existing, true);
$result[(string) $id] = in_array((string) $id, $existingIds, true);
}
return $result;
}
// ── Fetch ────────────────────────────────────────────────────────────────
public function fetch(string $tenantId, string $userId, string|int $serviceId): ?Service
/**
* Retrieve a single service by ID
*/
public function fetch(string $tenantId, string $userId, string|int $serviceId): ?array
{
$document = $this->dataStore->selectCollection(self::COLLECTION_NAME)->findOne([
'tid' => $tenantId,
@@ -112,57 +108,64 @@ class ServiceStore
$document['identity']['secret'] = $this->crypto->decrypt($document['identity']['secret']);
}
return (new Service())->fromStore($document);
return $document;
}
// ── Create ───────────────────────────────────────────────────────────────
public function create(string $tenantId, string $userId, Service $service): Service
/**
* Create a new service
*/
public function create(string $tenantId, string $userId, Service $service): array
{
$document = $service->toStore();
// prepare document for insertion
$document['tid'] = $tenantId;
$document['uid'] = $userId;
$document['sid'] = UUID::v4();
$document['createdOn'] = new \MongoDB\BSON\UTCDateTime();
$document['createdOn'] = new \MongoDB\BSON\UTCDateTime();
$document['modifiedOn'] = new \MongoDB\BSON\UTCDateTime();
if (isset($document['identity']['secret'])) {
$document['identity']['secret'] = $this->crypto->encrypt($document['identity']['secret']);
}
$this->dataStore->selectCollection(self::COLLECTION_NAME)->insertOne($document);
$result = $this->dataStore->selectCollection(self::COLLECTION_NAME)->insertOne($document);
return (new Service())->fromStore($document);
return $document;
}
// ── Modify ───────────────────────────────────────────────────────────────
public function modify(string $tenantId, string $userId, Service $service): Service
/**
* Modify an existing service
*/
public function modify(string $tenantId, string $userId, Service $service): array
{
$serviceId = $service->identifier();
if (empty($serviceId)) {
throw new \InvalidArgumentException('Service ID is required for update');
}
// prepare document for modification
$document = $service->toStore();
$document['modifiedOn'] = new \MongoDB\BSON\UTCDateTime();
if (isset($document['identity']['secret'])) {
$document['identity']['secret'] = $this->crypto->encrypt($document['identity']['secret']);
}
unset($document['sid'], $document['tid'], $document['uid'], $document['createdOn']);
$this->dataStore->selectCollection(self::COLLECTION_NAME)->updateOne(
['tid' => $tenantId, 'uid' => $userId, 'sid' => (string)$serviceId],
['$set' => $document],
[
'tid' => $tenantId,
'uid' => $userId,
'sid' => (string)$serviceId,
],
['$set' => $document]
);
return (new Service())->fromStore($document);
return $document;
}
// ── Delete ───────────────────────────────────────────────────────────────
/**
* Delete a service
*/
public function delete(string $tenantId, string $userId, string|int $serviceId): bool
{
$result = $this->dataStore->selectCollection(self::COLLECTION_NAME)->deleteOne([
@@ -173,4 +176,5 @@ class ServiceStore
return $result->getDeletedCount() > 0;
}
}