refactor: remove sources selector in backend
Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
@@ -24,9 +24,6 @@ use KTXF\Resource\Identifier\ResourceIdentifier;
|
||||
use KTXF\Resource\Identifier\ResourceIdentifiers;
|
||||
use KTXF\Resource\Identifier\ServiceIdentifier;
|
||||
use KTXF\Resource\Provider\ResourceServiceLocationInterface;
|
||||
use KTXF\Resource\Selector\CollectionSelector;
|
||||
use KTXF\Resource\Selector\ServiceSelector;
|
||||
use KTXF\Resource\Selector\SourceSelector;
|
||||
use KTXF\Routing\Attributes\AuthenticatedRoute;
|
||||
use KTXM\MailManager\Manager;
|
||||
use Psr\Log\LoggerInterface;
|
||||
@@ -41,6 +38,7 @@ class DefaultController extends ControllerAbstract {
|
||||
private const ERR_MISSING_SOURCES = 'Missing parameter: sources';
|
||||
private const ERR_MISSING_TARGET = 'Missing parameter: target';
|
||||
private const ERR_MISSING_TARGETS = 'Missing parameter: targets';
|
||||
private const ERR_MISSING_SENDER = 'Missing parameter: sender';
|
||||
private const ERR_INVALID_OPERATION = 'Invalid operation: ';
|
||||
private const ERR_INVALID_PROVIDER = 'Invalid parameter: provider must be a string';
|
||||
private const ERR_INVALID_SERVICE = 'Invalid parameter: service must be a string';
|
||||
@@ -48,6 +46,7 @@ class DefaultController extends ControllerAbstract {
|
||||
private const ERR_INVALID_SOURCES = 'Invalid parameter: sources must be an array';
|
||||
private const ERR_INVALID_TARGET = 'Invalid parameter: target must be an array';
|
||||
private const ERR_INVALID_TARGETS = 'Invalid parameter: targets must be an array';
|
||||
private const ERR_INVALID_SENDER = 'Invalid parameter: sender must be a string';
|
||||
private const ERR_INVALID_DATA = 'Invalid parameter: data must be an array';
|
||||
|
||||
public function __construct(
|
||||
@@ -172,40 +171,48 @@ class DefaultController extends ControllerAbstract {
|
||||
|
||||
private function providerList(string $tenantId, string $userId, array $data): mixed {
|
||||
|
||||
$sources = null;
|
||||
if (isset($data['sources']) && is_array($data['sources'])) {
|
||||
$sources = new SourceSelector();
|
||||
$sources->jsonDeserialize($data['sources']);
|
||||
}
|
||||
if (isset($data['targets'])) {
|
||||
if (!is_array($data['targets'])) {
|
||||
throw new InvalidArgumentException(self::ERR_INVALID_TARGETS);
|
||||
}
|
||||
|
||||
return $this->manager->providerList($tenantId, $userId, $sources);
|
||||
foreach ($data['targets'] as $target) {
|
||||
if (!is_string($target)) {
|
||||
throw new InvalidArgumentException(self::ERR_INVALID_TARGETS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->manager->providerList($tenantId, $userId, $data['targets'] ?? []);
|
||||
|
||||
}
|
||||
|
||||
private function providerFetch(string $tenantId, string $userId, array $data): mixed {
|
||||
|
||||
if (!isset($data['identifier'])) {
|
||||
throw new InvalidArgumentException(self::ERR_MISSING_IDENTIFIER);
|
||||
if (!isset($data['target'])) {
|
||||
throw new InvalidArgumentException(self::ERR_MISSING_TARGET);
|
||||
}
|
||||
if (!is_string($data['identifier'])) {
|
||||
throw new InvalidArgumentException(self::ERR_INVALID_IDENTIFIER);
|
||||
if (!is_string($data['target'])) {
|
||||
throw new InvalidArgumentException(self::ERR_INVALID_TARGET);
|
||||
}
|
||||
|
||||
return $this->manager->providerFetch($tenantId, $userId, $data['identifier']);
|
||||
return $this->manager->providerFetch($tenantId, $userId, $data['target']);
|
||||
|
||||
}
|
||||
|
||||
private function providerExtant(string $tenantId, string $userId, array $data): mixed {
|
||||
|
||||
if (!isset($data['sources'])) {
|
||||
throw new InvalidArgumentException(self::ERR_MISSING_SOURCES);
|
||||
}
|
||||
if (!is_array($data['sources'])) {
|
||||
throw new InvalidArgumentException(self::ERR_INVALID_SOURCES);
|
||||
}
|
||||
$sources = new SourceSelector();
|
||||
$sources->jsonDeserialize($data['sources']);
|
||||
if (!isset($data['targets'])) {
|
||||
throw new InvalidArgumentException(self::ERR_MISSING_TARGETS);
|
||||
}
|
||||
|
||||
return $this->manager->providerExtant($tenantId, $userId, $sources);
|
||||
foreach ($data['targets'] as $target) {
|
||||
if (!is_string($target)) {
|
||||
throw new InvalidArgumentException(self::ERR_INVALID_TARGETS);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->manager->providerExtant($tenantId, $userId, $data['targets']);
|
||||
|
||||
}
|
||||
|
||||
@@ -213,13 +220,17 @@ class DefaultController extends ControllerAbstract {
|
||||
|
||||
private function serviceList(string $tenantId, string $userId, array $data): mixed {
|
||||
|
||||
$sources = null;
|
||||
if (isset($data['sources']) && is_array($data['sources'])) {
|
||||
$sources = new SourceSelector();
|
||||
$sources->jsonDeserialize($data['sources']);
|
||||
$targets = null;
|
||||
if (isset($data['targets']) && is_array($data['targets'])) {
|
||||
$targets = ResourceIdentifiers::fromArray($data['targets']);
|
||||
foreach ($targets as $target) {
|
||||
if (!$target instanceof CollectionIdentifier && !$target instanceof ServiceIdentifier) {
|
||||
throw new InvalidArgumentException('Invalid parameter: targets must contain provider:service, provider:service:collection, or provider:service:collection:entity identifiers');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->manager->serviceList($tenantId, $userId, $sources);
|
||||
return $this->manager->serviceList($tenantId, $userId, $targets);
|
||||
|
||||
}
|
||||
|
||||
@@ -243,16 +254,20 @@ class DefaultController extends ControllerAbstract {
|
||||
|
||||
private function serviceExtant(string $tenantId, string $userId, array $data): mixed {
|
||||
|
||||
if (!isset($data['sources'])) {
|
||||
throw new InvalidArgumentException(self::ERR_MISSING_SOURCES);
|
||||
if (!isset($data['targets'])) {
|
||||
throw new InvalidArgumentException(self::ERR_MISSING_TARGETS);
|
||||
}
|
||||
if (!is_array($data['sources'])) {
|
||||
throw new InvalidArgumentException(self::ERR_INVALID_SOURCES);
|
||||
if (!is_array($data['targets'])) {
|
||||
throw new InvalidArgumentException(self::ERR_INVALID_TARGETS);
|
||||
}
|
||||
$targets = ResourceIdentifiers::fromArray($data['targets']);
|
||||
foreach ($targets as $target) {
|
||||
if (!$target instanceof ServiceIdentifier) {
|
||||
throw new InvalidArgumentException('Invalid parameter: targets must contain provider:service identifiers');
|
||||
}
|
||||
}
|
||||
$sources = new SourceSelector();
|
||||
$sources->jsonDeserialize($data['sources']);
|
||||
|
||||
return $this->manager->serviceExtant($tenantId, $userId, $sources);
|
||||
return $this->manager->serviceExtant($tenantId, $userId, $targets);
|
||||
}
|
||||
|
||||
private function serviceCreate(string $tenantId, string $userId, array $data): mixed {
|
||||
@@ -404,14 +419,12 @@ class DefaultController extends ControllerAbstract {
|
||||
private function collectionList(string $tenantId, string $userId, array $data): mixed {
|
||||
$sources = null;
|
||||
if (isset($data['sources']) && is_array($data['sources'])) {
|
||||
// TODO: Refactor to use identifiers directly
|
||||
$sources = ResourceIdentifiers::fromArray($data['sources']);
|
||||
foreach ($sources as $source) {
|
||||
if (!$source instanceof CollectionIdentifier && !$source instanceof ServiceIdentifier) {
|
||||
throw new InvalidArgumentException('Invalid parameter: sources must contain provider:service, provider:service:collection, or provider:service:collection:entity identifiers');
|
||||
}
|
||||
}
|
||||
$sources = $this->createSourceSelectorFromIdentifiers($sources);
|
||||
}
|
||||
|
||||
$filter = $data['filter'] ?? null;
|
||||
@@ -428,7 +441,6 @@ class DefaultController extends ControllerAbstract {
|
||||
throw new InvalidArgumentException(self::ERR_INVALID_TARGETS);
|
||||
}
|
||||
|
||||
// TODO: Refactor to use identifiers directly
|
||||
$targetIdentifiers = ResourceIdentifiers::fromArray($data['targets']);
|
||||
foreach ($targetIdentifiers as $targetIdentifier) {
|
||||
if (!$targetIdentifier instanceof CollectionIdentifier) {
|
||||
@@ -436,16 +448,11 @@ class DefaultController extends ControllerAbstract {
|
||||
}
|
||||
}
|
||||
|
||||
$list = [];
|
||||
foreach ($targetIdentifiers as $targetIdentifier) {
|
||||
$list[(string)$targetIdentifier] = $this->manager->collectionFetch(
|
||||
$tenantId,
|
||||
$userId,
|
||||
$targetIdentifier->provider(),
|
||||
$targetIdentifier->service(),
|
||||
$targetIdentifier->collection()
|
||||
);
|
||||
}
|
||||
$list = $this->manager->collectionFetch(
|
||||
$tenantId,
|
||||
$userId,
|
||||
$targetIdentifier
|
||||
);
|
||||
return $list;
|
||||
}
|
||||
|
||||
@@ -457,14 +464,12 @@ class DefaultController extends ControllerAbstract {
|
||||
throw new InvalidArgumentException(self::ERR_INVALID_TARGETS);
|
||||
}
|
||||
|
||||
// TODO: Refactor to use identifiers directly
|
||||
$sources = ResourceIdentifiers::fromArray($data['targets']);
|
||||
foreach ($sources as $source) {
|
||||
if (!$source instanceof CollectionIdentifier) {
|
||||
throw new InvalidArgumentException('Invalid parameter: targets must contain provider:service, provider:service:collection, or provider:service:collection:entity identifiers');
|
||||
}
|
||||
}
|
||||
$sources = $this->createSourceSelectorFromIdentifiers($sources);
|
||||
|
||||
return $this->manager->collectionExtant($tenantId, $userId, $sources);
|
||||
}
|
||||
@@ -612,8 +617,6 @@ class DefaultController extends ControllerAbstract {
|
||||
}
|
||||
}
|
||||
|
||||
$sources = $this->createSourceSelectorFromIdentifiers($sources);
|
||||
|
||||
$filter = $data['filter'] ?? null;
|
||||
$sort = $data['sort'] ?? null;
|
||||
$range = $data['range'] ?? null;
|
||||
@@ -637,8 +640,6 @@ class DefaultController extends ControllerAbstract {
|
||||
}
|
||||
}
|
||||
|
||||
$sources = $this->createSourceSelectorFromIdentifiers($sources);
|
||||
|
||||
$filter = $data['filter'] ?? null;
|
||||
$sort = $data['sort'] ?? null;
|
||||
$range = $data['range'] ?? null;
|
||||
@@ -696,31 +697,39 @@ class DefaultController extends ControllerAbstract {
|
||||
}
|
||||
|
||||
private function entityExtant(string $tenantId, string $userId, array $data): mixed {
|
||||
if (!isset($data['sources'])) {
|
||||
throw new InvalidArgumentException(self::ERR_MISSING_SOURCES);
|
||||
if (!isset($data['targets'])) {
|
||||
throw new InvalidArgumentException(self::ERR_MISSING_TARGETS);
|
||||
}
|
||||
if (!is_array($data['sources'])) {
|
||||
throw new InvalidArgumentException(self::ERR_INVALID_SOURCES);
|
||||
if (!is_array($data['targets'])) {
|
||||
throw new InvalidArgumentException(self::ERR_INVALID_TARGETS);
|
||||
}
|
||||
|
||||
$sources = new SourceSelector();
|
||||
$sources->jsonDeserialize($data['sources']);
|
||||
$targets = ResourceIdentifiers::fromArray($data['targets']);
|
||||
foreach ($targets as $target) {
|
||||
if (!$target instanceof CollectionIdentifier && !$target instanceof EntityIdentifier) {
|
||||
throw new InvalidArgumentException('Invalid parameter: targets must contain provider:service:collection or provider:service:collection:entity identifiers');
|
||||
}
|
||||
}
|
||||
|
||||
return $this->manager->entityExtant($tenantId, $userId, $sources);
|
||||
return $this->manager->entityExtant($tenantId, $userId, $targets);
|
||||
}
|
||||
|
||||
private function entityDelta(string $tenantId, string $userId, array $data): mixed {
|
||||
if (!isset($data['sources'])) {
|
||||
throw new InvalidArgumentException(self::ERR_MISSING_SOURCES);
|
||||
if (!isset($data['targets'])) {
|
||||
throw new InvalidArgumentException(self::ERR_MISSING_TARGETS);
|
||||
}
|
||||
if (!is_array($data['sources'])) {
|
||||
throw new InvalidArgumentException(self::ERR_INVALID_SOURCES);
|
||||
if (!is_array($data['targets'])) {
|
||||
throw new InvalidArgumentException(self::ERR_INVALID_TARGETS);
|
||||
}
|
||||
|
||||
$sources = new SourceSelector();
|
||||
$sources->jsonDeserialize($data['sources']);
|
||||
$targets = ResourceIdentifiers::fromArray($data['targets']);
|
||||
foreach ($targets as $target) {
|
||||
if (!$target instanceof CollectionIdentifier && !$target instanceof EntityIdentifier) {
|
||||
throw new InvalidArgumentException('Invalid parameter: targets must contain provider:service:collection or provider:service:collection:signature identifiers');
|
||||
}
|
||||
}
|
||||
|
||||
return $this->manager->entityDelta($tenantId, $userId, $sources);
|
||||
return $this->manager->entityDelta($tenantId, $userId, $targets);
|
||||
}
|
||||
|
||||
private function entityPatch(string $tenantId, string $userId, array $data): mixed {
|
||||
@@ -891,47 +900,4 @@ class DefaultController extends ControllerAbstract {
|
||||
return $results;
|
||||
}
|
||||
|
||||
private function createSourceSelectorFromIdentifiers(ResourceIdentifiers $identifiers): SourceSelector {
|
||||
$sources = new SourceSelector();
|
||||
|
||||
foreach ($identifiers as $identifier) {
|
||||
if (!$identifier instanceof ServiceIdentifier) {
|
||||
throw new InvalidArgumentException('Invalid parameter: sources must contain provider:service, provider:service:collection, or provider:service:collection:entity identifiers');
|
||||
}
|
||||
|
||||
$provider = $identifier->provider();
|
||||
$service = $identifier->service();
|
||||
|
||||
if (!isset($sources[$provider])) {
|
||||
$sources[$provider] = new ServiceSelector();
|
||||
}
|
||||
|
||||
$serviceSelector = $sources[$provider];
|
||||
if (!$serviceSelector instanceof ServiceSelector) {
|
||||
throw new InvalidArgumentException('Invalid parameter: sources must contain provider:service:collection selectors');
|
||||
}
|
||||
|
||||
if ($identifier instanceof ServiceIdentifier && !$identifier instanceof CollectionIdentifier) {
|
||||
$serviceSelector[$service] = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset($serviceSelector[$service]) && $serviceSelector[$service] === true) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($serviceSelector[$service])) {
|
||||
$serviceSelector[$service] = new CollectionSelector();
|
||||
}
|
||||
|
||||
$collectionSelector = $serviceSelector[$service];
|
||||
if (!$collectionSelector instanceof CollectionSelector) {
|
||||
throw new InvalidArgumentException('Invalid parameter: sources must contain provider:service:collection selectors');
|
||||
}
|
||||
|
||||
$collectionSelector[$identifier->collection()] = true;
|
||||
}
|
||||
|
||||
return $sources;
|
||||
}
|
||||
}
|
||||
|
||||
+168
-186
@@ -34,10 +34,6 @@ use KTXF\Resource\Provider\ResourceServiceIdentityInterface;
|
||||
use KTXF\Resource\Provider\ResourceServiceLocationInterface;
|
||||
use KTXF\Resource\Range\RangeAnchorType;
|
||||
use KTXF\Resource\Range\RangeType;
|
||||
use KTXF\Resource\Selector\CollectionSelector;
|
||||
use KTXF\Resource\Selector\EntitySelector;
|
||||
use KTXF\Resource\Selector\ServiceSelector;
|
||||
use KTXF\Resource\Selector\SourceSelector;
|
||||
use KTXF\Resource\Sort\ISort;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
@@ -56,15 +52,13 @@ class Manager {
|
||||
/**
|
||||
* Retrieve available providers
|
||||
*
|
||||
* @param SourceSelector|null $sources collection of provider identifiers
|
||||
* @param ResourceIdentifiers|null $sources collection of provider identifiers
|
||||
*
|
||||
* @return array<string,ProviderBaseInterface> collection of available providers e.g. ['provider1' => IProvider, 'provider2' => IProvider]
|
||||
*/
|
||||
public function providerList(string $tenantId, string $userId, ?SourceSelector $sources = null): array {
|
||||
// determine filter from sources
|
||||
$filter = ($sources !== null && $sources->identifiers() !== []) ? $sources->identifiers() : null;
|
||||
public function providerList(string $tenantId, string $userId, array|null $targets = []): array {
|
||||
// retrieve providers from provider manager
|
||||
return $this->providerManager->providers(ProviderBaseInterface::TYPE_MAIL, $filter);
|
||||
return $this->providerManager->providers(ProviderBaseInterface::TYPE_MAIL, $targets ?: null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -77,27 +71,27 @@ class Manager {
|
||||
* @return ProviderBaseInterface
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function providerFetch(string $tenantId, string $userId, string $provider): ProviderBaseInterface {
|
||||
public function providerFetch(string $tenantId, string $userId, string $target): ProviderBaseInterface {
|
||||
// retrieve provider
|
||||
$providers = $this->providerList($tenantId, $userId, new SourceSelector([$provider => true]));
|
||||
if (!isset($providers[$provider])) {
|
||||
throw new InvalidArgumentException("Provider '$provider' not found");
|
||||
$providers = $this->providerList($tenantId, $userId, [$target]);
|
||||
if (!isset($providers[$target])) {
|
||||
throw new InvalidArgumentException("Provider '$target' not found");
|
||||
}
|
||||
return $providers[$provider];
|
||||
return $providers[$target];
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm which providers are available
|
||||
*
|
||||
* @param SourceSelector|null $sources collection of provider identifiers to confirm
|
||||
* @param array<string> $targets collection of provider identifiers to confirm
|
||||
*
|
||||
* @return array<string,bool> collection of providers and their availability status e.g. ['provider1' => true, 'provider2' => false]
|
||||
*/
|
||||
public function providerExtant(string $tenantId, string $userId, SourceSelector $sources): array {
|
||||
public function providerExtant(string $tenantId, string $userId, array $targets): array {
|
||||
// determine which providers are available
|
||||
$providersResolved = $this->providerList($tenantId, $userId, $sources);
|
||||
$providersResolved = $this->providerList($tenantId, $userId, $targets);
|
||||
$providersAvailable = array_keys($providersResolved);
|
||||
$providersUnavailable = array_diff($sources->identifiers(), $providersAvailable);
|
||||
$providersUnavailable = array_diff($targets, $providersAvailable);
|
||||
// construct response data
|
||||
$responseData = array_merge(
|
||||
array_fill_keys($providersAvailable, true),
|
||||
@@ -111,18 +105,24 @@ class Manager {
|
||||
*
|
||||
* @param string $tenantId tenant identifier
|
||||
* @param string $userId user identifier
|
||||
* @param SourceSelector|null $sources list of provider and service identifiers
|
||||
* @param ResourceIdentifiers|null $targets list of provider and service identifiers
|
||||
*
|
||||
* @return array<string,<string,ServiceBaseInterface>> collections of available services e.g. ['provider1' => ['service1' => IServiceBase], 'provider2' => ['service2' => IServiceBase]]
|
||||
*/
|
||||
public function serviceList(string $tenantId, string $userId, ?SourceSelector $sources = null): array {
|
||||
public function serviceList(string $tenantId, string $userId, ?ResourceIdentifiers $targets = null): array {
|
||||
// retrieve providers
|
||||
$providers = $this->providerList($tenantId, $userId, $sources);
|
||||
$providerFilter = $targets !== null ? $targets->providers() : null;
|
||||
$providers = $this->providerList($tenantId, $userId, $providerFilter);
|
||||
// retrieve services for each provider
|
||||
$responseData = [];
|
||||
foreach ($providers as $provider) {
|
||||
$serviceFilter = $sources[$provider->identifier()] instanceof ServiceSelector ? $sources[$provider->identifier()]->identifiers() : [];
|
||||
$services = $provider->serviceList($tenantId, $userId, $serviceFilter);
|
||||
if ($targets !== null) {
|
||||
$servicesSelected = $targets?->byProvider($provider->identifier()) ?: [];
|
||||
$servicesFilter = $servicesSelected->services();
|
||||
} else {
|
||||
$servicesFilter = [];
|
||||
}
|
||||
$services = $provider->serviceList($tenantId, $userId, $servicesFilter);
|
||||
$responseData[$provider->identifier()] = $services;
|
||||
}
|
||||
return $responseData;
|
||||
@@ -154,24 +154,23 @@ class Manager {
|
||||
*
|
||||
* @param string $tenantId tenant identifier
|
||||
* @param string $userId user identifier
|
||||
* @param SourceSelector|null $sources collection of provider and service identifiers to confirm
|
||||
* @param ResourceIdentifiers $targets collection of provider and service identifiers to confirm
|
||||
*
|
||||
* @return array<string,bool> collection of providers and their availability status e.g. ['provider1' => ['service1' => false], 'provider2' => ['service2' => true, 'service3' => true]]
|
||||
*/
|
||||
public function serviceExtant(string $tenantId, string $userId, SourceSelector $sources): array {
|
||||
// retrieve providers
|
||||
$providers = $this->providerList($tenantId, $userId, $sources);
|
||||
$providersRequested = $sources->identifiers();
|
||||
public function serviceExtant(string $tenantId, string $userId, ResourceIdentifiers $targets): array {
|
||||
// retrieve available providers
|
||||
$providersRequested = $targets->providers();
|
||||
$providers = $this->providerList($tenantId, $userId, $providersRequested);
|
||||
$providersUnavailable = array_diff($providersRequested, array_keys($providers));
|
||||
|
||||
// initialize response with unavailable providers
|
||||
$responseData = array_fill_keys($providersUnavailable, false);
|
||||
|
||||
// retrieve services for each available provider
|
||||
foreach ($providers as $provider) {
|
||||
$serviceSelector = $sources[$provider->identifier()];
|
||||
$serviceAvailability = $provider->serviceExtant($tenantId, $userId, ...$serviceSelector->identifiers());
|
||||
$responseData[$provider->identifier()] = $serviceAvailability;
|
||||
foreach ($providers as $providerId => $provider) {
|
||||
$servicesRequested = $targets->byProvider($providerId)->services();
|
||||
$responseData[$providerId] = $provider->serviceExtant($tenantId, $userId, ...$servicesRequested);
|
||||
}
|
||||
return $responseData;
|
||||
}
|
||||
@@ -342,7 +341,7 @@ class Manager {
|
||||
string|null $location = null,
|
||||
string|null $secret = null
|
||||
): \Generator {
|
||||
$providers = $this->providerList($tenantId, $userId, $providerId !== null ? new SourceSelector([$providerId => true]) : null);
|
||||
$providers = $this->providerList($tenantId, $userId, $providerId !== null ? [$providerId] : null);
|
||||
|
||||
foreach ($providers as $currentProviderId => $provider) {
|
||||
if ($provider instanceof ProviderServiceDiscoverInterface === false) {
|
||||
@@ -459,26 +458,23 @@ class Manager {
|
||||
*
|
||||
* @param string $tenantId Tenant identifier
|
||||
* @param string|null $userId User identifier for context
|
||||
* @param SourceSelector|null $sources Provider/service sources
|
||||
* @param ResourceIdentifiers|null $targets Provider/service sources
|
||||
* @param IFilter|null $filter Collection filter
|
||||
* @param ISort|null $sort Collection sort
|
||||
*
|
||||
* @return array<string, array<string|int, array<string|int, ICollectionBase>>> Collections grouped by provider/service
|
||||
*/
|
||||
public function collectionList(string $tenantId, ?string $userId, ?SourceSelector $sources = null, ?IFilter $filter = null, ?ISort $sort = null): array {
|
||||
public function collectionList(string $tenantId, ?string $userId, ?ResourceIdentifiers $targets = null, ?IFilter $filter = null, ?ISort $sort = null): array {
|
||||
// confirm that sources are provided
|
||||
if ($sources === null) {
|
||||
$sources = new SourceSelector([]);
|
||||
if ($targets === null) {
|
||||
$targets = new ResourceIdentifiers([]);
|
||||
}
|
||||
// retrieve providers
|
||||
$providers = $this->providerList($tenantId, $userId, $sources);
|
||||
$aggregateServices = $this->serviceList($tenantId, $userId, $targets);
|
||||
// retrieve services for each provider
|
||||
$responseData = [];
|
||||
foreach ($providers as $provider) {
|
||||
$serviceFilter = $sources[$provider->identifier()] instanceof ServiceSelector ? $sources[$provider->identifier()]->identifiers() : [];
|
||||
/** @var ServiceBaseInterface[] $services */
|
||||
$services = $provider->serviceList($tenantId, $userId, $serviceFilter);
|
||||
// retrieve collections for each service
|
||||
// retrieve collections for each service
|
||||
foreach ($aggregateServices as $services) {
|
||||
foreach ($services as $service) {
|
||||
if ($service->getEnabled() === false) {
|
||||
continue;
|
||||
@@ -499,72 +495,23 @@ class Manager {
|
||||
$collectionSort->condition($attribute, $direction);
|
||||
}
|
||||
}
|
||||
$collections = $service->collectionList('', $collectionFilter, $collectionSort);
|
||||
|
||||
$collectionIdentifiers = $targets->byProvider($service->provider())->byService($service->identifier())->collections();
|
||||
if ($collectionIdentifiers !== []) {
|
||||
foreach ($collectionIdentifiers as $collectionIdentifier) {
|
||||
$collections = array_merge($collections ?? [], $service->collectionList($collectionIdentifier, $collectionFilter, $collectionSort));
|
||||
}
|
||||
} else {
|
||||
$collections = $service->collectionList('', $collectionFilter, $collectionSort);
|
||||
}
|
||||
if ($collections !== []) {
|
||||
$responseData[$provider->identifier()][$service->identifier()] = $collections;
|
||||
$responseData[$service->provider()][$service->identifier()] = $collections;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $responseData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if collections exist
|
||||
*
|
||||
* @since 2025.05.01
|
||||
*
|
||||
* @param string $tenantId Tenant identifier
|
||||
* @param string|null $userId User identifier for context
|
||||
* @param SourceSelector $sources Collection sources with identifiers
|
||||
*
|
||||
* @return array<string, array<string|int, array<string|int, bool>>> Existence map grouped by provider/service
|
||||
*/
|
||||
public function collectionExtant(string $tenantId, ?string $userId, SourceSelector $sources): array {
|
||||
// retrieve available providers
|
||||
$providers = $this->providerList($tenantId, $userId, $sources);
|
||||
$providersRequested = $sources->identifiers();
|
||||
$providersUnavailable = array_diff($providersRequested, array_keys($providers));
|
||||
|
||||
// initialize response with unavailable providers
|
||||
$responseData = array_fill_keys($providersUnavailable, false);
|
||||
|
||||
// check services and collections for each available provider
|
||||
foreach ($providers as $provider) {
|
||||
// extract services for this provider
|
||||
$serviceSelector = $sources[$provider->identifier()];
|
||||
$servicesRequested = $serviceSelector->identifiers();
|
||||
/** @var ServiceBaseInterface[] $servicesAvailable */
|
||||
$servicesAvailable = $provider->serviceList($tenantId, $userId, $servicesRequested);
|
||||
$servicesUnavailable = array_diff($servicesRequested, array_keys($servicesAvailable));
|
||||
// mark unavailable services as false
|
||||
if ($servicesUnavailable !== []) {
|
||||
$responseData[$provider->identifier()] = array_fill_keys($servicesUnavailable, false);
|
||||
}
|
||||
// confirm collections for each available service
|
||||
foreach ($servicesAvailable as $service) {
|
||||
// omit disabled services
|
||||
if ($service->getEnabled() === false) {
|
||||
$responseData[$provider->identifier()][$service->identifier()] = false;
|
||||
continue;
|
||||
}
|
||||
// extract collections requested for this service
|
||||
$collectionSelector = $serviceSelector[$service->identifier()];
|
||||
$collectionsRequested = $collectionSelector instanceof CollectionSelector ? $collectionSelector->identifiers() : [];
|
||||
if ($collectionsRequested === []) {
|
||||
continue;
|
||||
}
|
||||
// check each requested collection
|
||||
$collectionsAvailable = $service->collectionExtant(...$collectionsRequested);
|
||||
$collectionsUnavailable = array_diff($collectionsRequested, array_keys($collectionsAvailable));
|
||||
$responseData[$provider->identifier()][$service->identifier()] = array_merge(
|
||||
$collectionsAvailable,
|
||||
array_fill_keys($collectionsUnavailable, false)
|
||||
);
|
||||
}
|
||||
}
|
||||
return $responseData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch a specific collection
|
||||
*
|
||||
@@ -578,14 +525,62 @@ class Manager {
|
||||
*
|
||||
* @return CollectionBaseInterface|null
|
||||
*/
|
||||
public function collectionFetch(string $tenantId, ?string $userId, string $providerId, string|int $serviceId, string|int $collectionId): ?CollectionBaseInterface {
|
||||
public function collectionFetch(string $tenantId, ?string $userId, CollectionIdentifier $target): ?CollectionBaseInterface {
|
||||
// retrieve service
|
||||
$service = $this->serviceFetch($tenantId, $userId, $providerId, $serviceId);
|
||||
if ($service === null || $service->getEnabled() === false) {
|
||||
return null;
|
||||
}
|
||||
$service = $this->serviceFetch($tenantId, $userId, $target->provider(), $target->service());
|
||||
// retrieve collection
|
||||
return $service->collectionFetch($collectionId);
|
||||
return $service->collectionFetch($target->collection());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if collections exist
|
||||
*
|
||||
* @since 2025.05.01
|
||||
*
|
||||
* @param string $tenantId Tenant identifier
|
||||
* @param string|null $userId User identifier for context
|
||||
* @param ResourceIdentifiers $targets Collection sources with identifiers
|
||||
*
|
||||
* @return array<string, array<string|int, array<string|int, bool>>> Existence map grouped by provider/service
|
||||
*/
|
||||
public function collectionExtant(string $tenantId, ?string $userId, ResourceIdentifiers $targets): array {
|
||||
// retrieve available services grouped by provider
|
||||
$aggregateServices = $this->serviceList($tenantId, $userId, $targets);
|
||||
// initialize response with unavailable providers marked as false
|
||||
$providersRequested = $targets->providers();
|
||||
$providersUnavailable = array_diff($providersRequested, array_keys($aggregateServices));
|
||||
$responseData = array_fill_keys($providersUnavailable, false);
|
||||
|
||||
// check services and collections for each available provider
|
||||
foreach ($aggregateServices as $providerId => $services) {
|
||||
// mark unavailable services as false
|
||||
$servicesRequested = $targets->byProvider($providerId)->services();
|
||||
$servicesUnavailable = array_diff($servicesRequested, array_keys($services));
|
||||
if ($servicesUnavailable !== []) {
|
||||
$responseData[$providerId] = array_fill_keys($servicesUnavailable, false);
|
||||
}
|
||||
// confirm collections for each available service
|
||||
foreach ($services as $service) {
|
||||
// omit disabled services
|
||||
if ($service->getEnabled() === false) {
|
||||
$responseData[$providerId][$service->identifier()] = false;
|
||||
continue;
|
||||
}
|
||||
// extract collections requested for this service
|
||||
$collectionsRequested = $targets->byProvider($providerId)->byService($service->identifier())->collections();
|
||||
if ($collectionsRequested === []) {
|
||||
continue;
|
||||
}
|
||||
// check each requested collection
|
||||
$collectionsAvailable = $service->collectionExtant(...$collectionsRequested);
|
||||
$collectionsUnavailable = array_diff($collectionsRequested, array_keys($collectionsAvailable));
|
||||
$responseData[$providerId][$service->identifier()] = array_merge(
|
||||
$collectionsAvailable,
|
||||
array_fill_keys($collectionsUnavailable, false)
|
||||
);
|
||||
}
|
||||
}
|
||||
return $responseData;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -730,31 +725,31 @@ class Manager {
|
||||
*
|
||||
* @param string $tenantId Tenant identifier
|
||||
* @param string $userId User identifier
|
||||
* @param SourceSelector $sources Message sources with collection identifiers
|
||||
* @param ResourceIdentifiers|null $targets Message sources with collection identifiers
|
||||
* @param array|null $filter Message filter
|
||||
* @param array|null $sort Message sort
|
||||
* @param array|null $range Message range/pagination
|
||||
*
|
||||
* @return array<string, array<string|int, array<string|int, array<string|int, IMessageBase>>>> Messages grouped by provider/service/collection
|
||||
*/
|
||||
public function entityListBulk(string $tenantId, string $userId, SourceSelector $sources, array|null $filter = null, array|null $sort = null, array|null $range = null): array {
|
||||
// retrieve providers
|
||||
$providers = $this->providerList($tenantId, $userId, $sources);
|
||||
public function entityListBulk(string $tenantId, string $userId, ?ResourceIdentifiers $targets = null, array|null $filter = null, array|null $sort = null, array|null $range = null): array {
|
||||
// confirm that sources are provided
|
||||
if ($targets === null) {
|
||||
$targets = new ResourceIdentifiers([]);
|
||||
}
|
||||
// retrieve services for each provider
|
||||
$aggregateServices = $this->serviceList($tenantId, $userId, $targets);
|
||||
// retrieve entities for each service
|
||||
$responseData = [];
|
||||
foreach ($providers as $provider) {
|
||||
// retrieve services for each provider
|
||||
$serviceSelector = $sources[$provider->identifier()];
|
||||
$servicesSelected = $provider->serviceList($tenantId,$userId, $serviceSelector->identifiers());
|
||||
foreach ($aggregateServices as $services) {
|
||||
/** @var ServiceBaseInterface $service */
|
||||
foreach ($servicesSelected as $service) {
|
||||
foreach ($services as $service) {
|
||||
// omit disabled services
|
||||
if ($service->getEnabled() === false) {
|
||||
continue;
|
||||
}
|
||||
// retrieve collections for each service
|
||||
$collectionSelector = $serviceSelector[$service->identifier()];
|
||||
$collectionSelected = $collectionSelector instanceof CollectionSelector ? $collectionSelector->identifiers() : [];
|
||||
$collectionSelected = $targets->byProvider($service->provider())->byService($service->identifier())->collections();
|
||||
if ($collectionSelected === []) {
|
||||
$collections = $service->collectionList('');
|
||||
$collectionSelected = array_map(
|
||||
@@ -806,7 +801,7 @@ class Manager {
|
||||
if ($entities === []) {
|
||||
continue;
|
||||
}
|
||||
$responseData[$provider->identifier()][$service->identifier()][$collectionId] = $entities;
|
||||
$responseData[$service->provider()][$service->identifier()][$collectionId] = $entities;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -821,29 +816,29 @@ class Manager {
|
||||
*
|
||||
* @param string $tenantId Tenant identifier
|
||||
* @param string $userId User identifier
|
||||
* @param SourceSelector $sources Message sources with collection identifiers
|
||||
* @param ResourceIdentifiers|null $targets Message sources with collection identifiers
|
||||
* @param array|null $filter Message filter
|
||||
* @param array|null $sort Message sort
|
||||
* @param array|null $range Message range/pagination
|
||||
*
|
||||
* @return \Generator<EntityBaseInterface> Yields each entity as it is retrieved
|
||||
*/
|
||||
public function entityListStream(string $tenantId, string $userId, SourceSelector $sources, array|null $filter = null, array|null $sort = null, array|null $range = null): \Generator {
|
||||
// retrieve providers
|
||||
$providers = $this->providerList($tenantId, $userId, $sources);
|
||||
public function entityListStream(string $tenantId, string $userId, ?ResourceIdentifiers $targets = null, array|null $filter = null, array|null $sort = null, array|null $range = null): \Generator {
|
||||
// confirm that sources are provided
|
||||
if ($targets === null) {
|
||||
$targets = new ResourceIdentifiers([]);
|
||||
}
|
||||
// retrieve services for each provider
|
||||
foreach ($providers as $provider) {
|
||||
$serviceSelector = $sources[$provider->identifier()];
|
||||
$servicesSelected = $provider->serviceList($tenantId, $userId, $serviceSelector->identifiers());
|
||||
$aggregateServices = $this->serviceList($tenantId, $userId, $targets);
|
||||
foreach ($aggregateServices as $services) {
|
||||
/** @var ServiceBaseInterface $service */
|
||||
foreach ($servicesSelected as $service) {
|
||||
foreach ($services as $service) {
|
||||
// omit disabled services
|
||||
if ($service->getEnabled() === false) {
|
||||
continue;
|
||||
}
|
||||
// retrieve collections for each service
|
||||
$collectionSelector = $serviceSelector[$service->identifier()];
|
||||
$collectionSelected = $collectionSelector instanceof CollectionSelector ? $collectionSelector->identifiers() : [];
|
||||
$collectionSelected = $targets->byProvider($service->provider())->byService($service->identifier())->collections();
|
||||
if ($collectionSelected === []) {
|
||||
$collections = $service->collectionList('');
|
||||
$collectionSelected = array_map(
|
||||
@@ -971,43 +966,36 @@ class Manager {
|
||||
*
|
||||
* @param string $tenantId Tenant identifier
|
||||
* @param string|null $userId User identifier for context
|
||||
* @param SourceSelector $sources Message sources with identifiers
|
||||
* @param ResourceIdentifiers $targets Message sources with identifiers
|
||||
*
|
||||
* @return array<string, array<string|int, array<string|int, array<string|int, bool>>>> Existence map grouped by provider/service/collection
|
||||
*/
|
||||
public function entityExtant(string $tenantId, string $userId, SourceSelector $sources): array {
|
||||
// confirm that sources are provided
|
||||
if ($sources === null) {
|
||||
$sources = new SourceSelector([]);
|
||||
}
|
||||
// retrieve available providers
|
||||
$providers = $this->providerList($tenantId, $userId, $sources);
|
||||
$providersRequested = $sources->identifiers();
|
||||
$providersUnavailable = array_diff($providersRequested, array_keys($providers));
|
||||
// initialize response with unavailable providers
|
||||
public function entityExtant(string $tenantId, string $userId, ResourceIdentifiers $targets): array {
|
||||
// retrieve available services grouped by provider
|
||||
$aggregateServices = $this->serviceList($tenantId, $userId, $targets);
|
||||
// initialize response with unavailable providers marked as false
|
||||
$providersRequested = $targets->providers();
|
||||
$providersUnavailable = array_diff($providersRequested, array_keys($aggregateServices));
|
||||
$responseData = array_fill_keys($providersUnavailable, false);
|
||||
|
||||
// check services, collections, and entities for each available provider
|
||||
foreach ($providers as $provider) {
|
||||
// extract services requested for this provider
|
||||
$serviceSelector = $sources[$provider->identifier()];
|
||||
$servicesRequested = $serviceSelector->identifiers();
|
||||
/** @var ServiceBaseInterface[] $servicesAvailable */
|
||||
$servicesAvailable = $provider->serviceList($tenantId, $userId, $servicesRequested);
|
||||
$servicesUnavailable = array_diff($servicesRequested, array_keys($servicesAvailable));
|
||||
foreach ($aggregateServices as $providerId => $services) {
|
||||
// mark unavailable services as false
|
||||
$servicesRequested = $targets->byProvider($providerId)->services();
|
||||
$servicesUnavailable = array_diff($servicesRequested, array_keys($services));
|
||||
if ($servicesUnavailable !== []) {
|
||||
$responseData[$provider->identifier()] = array_fill_keys($servicesUnavailable, false);
|
||||
$responseData[$providerId] = array_fill_keys($servicesUnavailable, false);
|
||||
}
|
||||
// check collections and entities for each available service
|
||||
foreach ($servicesAvailable as $service) {
|
||||
foreach ($services as $service) {
|
||||
// omit disabled services
|
||||
if ($service->getEnabled() === false) {
|
||||
$responseData[$provider->identifier()][$service->identifier()] = false;
|
||||
$responseData[$providerId][$service->identifier()] = false;
|
||||
continue;
|
||||
}
|
||||
// extract collections requested for this service
|
||||
$collectionSelector = $serviceSelector[$service->identifier()];
|
||||
$collectionsRequested = $collectionSelector instanceof CollectionSelector ? $collectionSelector->identifiers() : [];
|
||||
$serviceTargets = $targets->byProvider($providerId)->byService($service->identifier());
|
||||
$collectionsRequested = $serviceTargets->collections();
|
||||
if ($collectionsRequested === []) {
|
||||
continue;
|
||||
}
|
||||
@@ -1017,19 +1005,18 @@ class Manager {
|
||||
$collectionExists = $service->collectionExtant((string)$collectionId);
|
||||
if (!$collectionExists) {
|
||||
// collection doesn't exist, mark as false
|
||||
$responseData[$provider->identifier()][$service->identifier()][$collectionId] = false;
|
||||
$responseData[$providerId][$service->identifier()][$collectionId] = false;
|
||||
continue;
|
||||
}
|
||||
// extract entity identifiers from collection selector
|
||||
$entitySelector = $collectionSelector[$collectionId];
|
||||
// handle both array of entity IDs and boolean true (meaning check if collection exists)
|
||||
if ($entitySelector instanceof EntitySelector) {
|
||||
// check specific entities within the collection
|
||||
$responseData[$provider->identifier()][$service->identifier()][$collectionId] = $service->entityExtant($collectionId, ...$entitySelector->identifiers());
|
||||
} elseif ($entitySelector === true) {
|
||||
// extract entity identifiers requested for this collection
|
||||
$entitiesRequested = $serviceTargets->byCollection($collectionId)->entities();
|
||||
if ($entitiesRequested === []) {
|
||||
// just checking if collection exists (already confirmed above)
|
||||
$responseData[$provider->identifier()][$service->identifier()][$collectionId] = true;
|
||||
$responseData[$providerId][$service->identifier()][$collectionId] = true;
|
||||
continue;
|
||||
}
|
||||
// check specific entities within the collection
|
||||
$responseData[$providerId][$service->identifier()][$collectionId] = $service->entityExtant($collectionId, ...$entitiesRequested);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1043,50 +1030,45 @@ class Manager {
|
||||
*
|
||||
* @param string $tenantId Tenant identifier
|
||||
* @param string|null $userId User identifier for context
|
||||
* @param SourceSelector $sources Message sources with signatures
|
||||
* @param ResourceIdentifiers $targets Message sources with signatures
|
||||
*
|
||||
* @return array<string, array<string|int, array<string|int, array>>> Delta grouped by provider/service/collection
|
||||
*/
|
||||
public function entityDelta(string $tenantId, string $userId, SourceSelector $sources): array {
|
||||
// confirm that sources are provided
|
||||
if ($sources === null) {
|
||||
$sources = new SourceSelector([]);
|
||||
}
|
||||
// retrieve providers
|
||||
$providers = $this->providerList($tenantId, $userId, $sources);
|
||||
$providersRequested = $sources->identifiers();
|
||||
$providersUnavailable = array_diff($providersRequested, array_keys($providers));
|
||||
// initialize response with unavailable providers
|
||||
public function entityDelta(string $tenantId, string $userId, ResourceIdentifiers $targets): array {
|
||||
// retrieve available services grouped by provider
|
||||
$aggregateServices = $this->serviceList($tenantId, $userId, $targets);
|
||||
// initialize response with unavailable providers marked as false
|
||||
$providersRequested = $targets->providers();
|
||||
$providersUnavailable = array_diff($providersRequested, array_keys($aggregateServices));
|
||||
$responseData = array_fill_keys($providersUnavailable, false);
|
||||
|
||||
// iterate through available providers
|
||||
foreach ($providers as $provider) {
|
||||
// extract services requested for this provider
|
||||
$serviceSelector = $sources[$provider->identifier()];
|
||||
$servicesRequested = $serviceSelector instanceof ServiceSelector ? $serviceSelector->identifiers() : [];
|
||||
/** @var ServiceBaseInterface[] $services */
|
||||
$services = $provider->serviceList($tenantId, $userId, $servicesRequested);
|
||||
foreach ($aggregateServices as $providerId => $services) {
|
||||
// mark unavailable services as false
|
||||
$servicesRequested = $targets->byProvider($providerId)->services();
|
||||
$servicesUnavailable = array_diff($servicesRequested, array_keys($services));
|
||||
if ($servicesUnavailable !== []) {
|
||||
$responseData[$provider->identifier()] = array_fill_keys($servicesUnavailable, false);
|
||||
$responseData[$providerId] = array_fill_keys($servicesUnavailable, false);
|
||||
}
|
||||
// iterate through available services
|
||||
foreach ($services as $service) {
|
||||
// omit disabled services
|
||||
if ($service->getEnabled() === false) {
|
||||
$responseData[$provider->identifier()][$service->identifier()] = false;
|
||||
$responseData[$providerId][$service->identifier()] = false;
|
||||
continue;
|
||||
}
|
||||
// extract collections requested for this service
|
||||
$collectionSelector = $serviceSelector[$service->identifier()];
|
||||
$collectionsRequested = $collectionSelector instanceof CollectionSelector ? $collectionSelector->identifiers() : [];
|
||||
$serviceTargets = $targets->byProvider($providerId)->byService($service->identifier());
|
||||
$collectionsRequested = $serviceTargets->collections();
|
||||
if ($collectionsRequested === []) {
|
||||
$responseData[$provider->identifier()][$service->identifier()] = false;
|
||||
$responseData[$providerId][$service->identifier()] = false;
|
||||
continue;
|
||||
}
|
||||
// check delta for each requested collection
|
||||
foreach ($collectionsRequested as $collection) {
|
||||
$entitySelector = $collectionSelector[$collection] ?? null;
|
||||
$responseData[$provider->identifier()][$service->identifier()][$collection] = $service->entityDelta($collection, $entitySelector);
|
||||
// signature for the collection is carried in the entity slot of the identifier
|
||||
$signature = $serviceTargets->byCollection($collection)->entities()[0] ?? '';
|
||||
$responseData[$providerId][$service->identifier()][$collection] = $service->entityDelta($collection, $signature);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user