feat: add services configuration accessors

Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
2026-09-07 13:39:16 -04:00
parent fbc0559a64
commit 09355d14a4
3 changed files with 89 additions and 12 deletions
@@ -14,6 +14,7 @@ class TenantConfiguration extends JsonSerializableObject
protected TenantFirewall $firewall; protected TenantFirewall $firewall;
protected TenantStores $stores; protected TenantStores $stores;
protected TenantPreview $preview; protected TenantPreview $preview;
protected array $services = [];
public function __construct() public function __construct()
{ {
@@ -36,6 +37,10 @@ class TenantConfiguration extends JsonSerializableObject
return $this->firewall; return $this->firewall;
} }
public function services(): array {
return $this->services;
}
public function stores(): TenantStores { public function stores(): TenantStores {
return $this->stores; return $this->stores;
} }
+11
View File
@@ -73,4 +73,15 @@ class TenantService
{ {
return $this->store->storeSettings($identifier, $settings); return $this->store->storeSettings($identifier, $settings);
} }
public function fetchServiceConfiguration(string $identifier, string $name): ?array
{
return $this->store->fetchServiceConfiguration($identifier, $name);
}
public function storeServiceConfiguration(string $identifier, string $name, array $configuration): bool
{
return $this->store->storeServiceConfiguration($identifier, $name, $configuration);
}
} }
+73 -12
View File
@@ -77,29 +77,40 @@ class TenantStore
$this->dataStore->selectCollection(self::COLLECTION_NAME)->deleteOne(['_id' => new ObjectId($id)]); $this->dataStore->selectCollection(self::COLLECTION_NAME)->deleteOne(['_id' => new ObjectId($id)]);
} }
/** // =========================================================================
* Atomically creates or replaces one logical store reference. // Configuration Operations
* // =========================================================================
* @param array{provider: string, service: string|int, namespace: string} $reference
*/ public function fetchConfiguration(string $identifier, string $path): ?array
public function storeConfigurationStore(string $identifier, string $name, array $reference): bool {
$entry = $this->dataStore->selectCollection(self::COLLECTION_NAME)->findOne(
['identifier' => $identifier],
['projection' => ['configuration.' . $path => 1]],
);
if (!$entry) {
return null;
}
$value = $this->readPath($entry, "configuration.{$path}");
return $value === null ? null : (array) $value;
}
public function storeConfiguration(string $identifier, string $path, array $value): bool
{ {
$result = $this->dataStore->selectCollection(self::COLLECTION_NAME)->updateOne( $result = $this->dataStore->selectCollection(self::COLLECTION_NAME)->updateOne(
['identifier' => $identifier], ['identifier' => $identifier],
['$set' => ["configuration.stores.{$name}" => $reference]], ['$set' => ['configuration.' . $path => $value]],
); );
return $result->getMatchedCount() > 0; return $result->getMatchedCount() > 0;
} }
/** public function removeConfiguration(string $identifier, string $path): ?bool
* Atomically removes one logical store reference.
*/
public function removeConfigurationStore(string $identifier, string $name): ?bool
{ {
$result = $this->dataStore->selectCollection(self::COLLECTION_NAME)->updateOne( $result = $this->dataStore->selectCollection(self::COLLECTION_NAME)->updateOne(
['identifier' => $identifier], ['identifier' => $identifier],
['$unset' => ["configuration.stores.{$name}" => '']], ['$unset' => ['configuration.' . $path => '']],
); );
if ($result->getMatchedCount() === 0) { if ($result->getMatchedCount() === 0) {
@@ -162,4 +173,54 @@ class TenantStore
return $result->getMatchedCount() > 0; return $result->getMatchedCount() > 0;
} }
/**
* Atomically creates or replaces one logical store reference.
*
* @param array{provider: string, service: string|int, namespace: string} $reference
*/
public function storeConfigurationStore(string $identifier, string $name, array $reference): bool
{
return $this->storeConfiguration($identifier, "stores.{$name}", $reference);
}
/**
* Atomically removes one logical store reference.
*/
public function removeConfigurationStore(string $identifier, string $name): ?bool
{
return $this->removeConfiguration($identifier, "stores.{$name}");
}
public function fetchServiceConfiguration(string $identifier, string $name): ?array
{
$this->validateServiceName($name);
return $this->fetchConfiguration($identifier, "services.{$name}");
}
/** Save one service atomically. */
public function storeServiceConfiguration(string $identifier, string $name, array $configuration): bool
{
$this->validateServiceName($name);
return $this->storeConfiguration($identifier, "services.{$name}", $configuration);
}
private function validateServiceName(string $name): void
{
if (preg_match('/^[a-z][a-z0-9_]*$/D', $name) !== 1) {
throw new \InvalidArgumentException('Invalid service name.');
}
}
private function readPath(array $data, string $path): mixed
{
$value = $data;
foreach (explode('.', $path) as $segment) {
if (!is_array($value) || !array_key_exists($segment, $value)) {
return null;
}
$value = $value[$segment];
}
return $value;
}
} }