diff --git a/composer.lock b/composer.lock index 0872a374..931d342f 100644 --- a/composer.lock +++ b/composer.lock @@ -2792,16 +2792,16 @@ }, { "name": "conduction/hydra-gates", - "version": "v1.7.3", + "version": "v1.8.0", "source": { "type": "git", "url": "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/ConductionNL/.github.git", - "reference": "9b9896abf87167e97b821d8ee86c5422f0b32e80" + "reference": "9fc64ab93f7a20b69f6b5912745ef9fc456c1cee" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ConductionNL/.github/zipball/9b9896abf87167e97b821d8ee86c5422f0b32e80", - "reference": "9b9896abf87167e97b821d8ee86c5422f0b32e80", + "url": "https://api.github.com/repos/ConductionNL/.github/zipball/9fc64ab93f7a20b69f6b5912745ef9fc456c1cee", + "reference": "9fc64ab93f7a20b69f6b5912745ef9fc456c1cee", "shasum": "" }, "require": { @@ -2818,6 +2818,11 @@ "schemas": "hydra-gates/scripts/schemas" } }, + "autoload": { + "psr-4": { + "OCA\\OpenRegister\\Contract\\": "hydra-gates/contracts/" + } + }, "notification-url": "https://packagist.org/downloads/", "license": [ "EUPL-1.2" @@ -2840,9 +2845,9 @@ "support": { "docs": "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/ConductionNL/.github/blob/main/hydra-gates/README.md", "issues": "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/ConductionNL/.github/issues", - "source": "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/ConductionNL/.github/tree/v1.7.3" + "source": "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/ConductionNL/.github/tree/v1.8.0" }, - "time": "2026-08-12T22:32:31+00:00" + "time": "2026-08-15T06:24:48+00:00" }, { "name": "consolidation/annotated-command", @@ -9978,9 +9983,9 @@ "platform": { "php": "^8.3" }, - "platform-dev": {}, + "platform-dev": [], "platform-overrides": { "php": "8.3" }, - "plugin-api-version": "2.9.0" + "plugin-api-version": "2.6.0" } diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 41ce0b95..451075d9 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -21,6 +21,7 @@ namespace OCA\SoftwareCatalog\AppInfo; use OCA\Decidesk\Event\DecisionConcludedEvent; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCA\OpenRegister\Event\ObjectCreatedEvent; use OCA\OpenRegister\Event\ObjectUpdatedEvent; use OCA\OpenRegister\Event\UserProfileUpdatedEvent; @@ -127,6 +128,22 @@ public function __construct() { * @spec openspec/specs/settings-service/spec.md */ public function register(IRegistrationContext $context): void { + + // ADR-084: services type-hint OpenRegister's PUBLISHED interface, never its + // concrete class, so this app's unit tests can mock a type they are able to + // load. Nextcloud autowires concrete classes across apps but not interfaces, + // so the binding has to be stated — and the composition root is where this + // app says how it is wired. + // + // An ALIAS, not a factory: it resolves when something actually asks for the + // interface, so an instance without OpenRegister fails at the route that + // needed the data rather than at registration. Both names are strings and + // neither triggers an autoload, which is what keeps ADR-083 rule 3's promise + // that the start screen still boots. + $context->registerServiceAlias( + ObjectServiceInterface::class, + 'OCA\OpenRegister\Service\ObjectService' + ); include_once __DIR__ . '/../../vendor/autoload.php'; $this->registerHandlerServices(context: $context); @@ -333,6 +350,10 @@ function ($container) { db: $container->get(IDBConnection::class), contactpersonHandler: $container->get(ContactPersonHandler::class), container: $container, + // ADR-084: the published contract, resolved through the alias + // registered above, not the concrete OpenRegister class. + objectService: $container->get(ObjectServiceInterface::class), + organisationMapper: $container->get('OCA\OpenRegister\Db\OrganisationMapper'), ); } ); @@ -356,7 +377,8 @@ function ($container) { return new GebruikSyncService( logger: $container->get('Psr\Log\LoggerInterface'), settingsService: $container->get(SettingsService::class), - container: $container + container: $container, + objectService: $container->get(ObjectServiceInterface::class), ); } ); diff --git a/lib/Controller/ContactpersonenController.php b/lib/Controller/ContactpersonenController.php index 865bc1be..0fa6a930 100644 --- a/lib/Controller/ContactpersonenController.php +++ b/lib/Controller/ContactpersonenController.php @@ -35,6 +35,8 @@ use OCP\Security\ISecureRandom; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; +use OCA\OpenRegister\Contract\ObjectServiceInterface; +use OCA\OpenRegister\Service\OrganisationService; /** * Controller for managing contactpersonen and their user accounts. @@ -152,6 +154,8 @@ public function __construct( ContainerInterface $container, ISecureRandom $secureRandom, LoggerInterface $logger, + private readonly ObjectServiceInterface $objectService, + private readonly OrganisationService $organisationService, ) { parent::__construct(appName: $appName, request: $request); $this->settingsService = $settingsService; @@ -201,7 +205,6 @@ public function getContactpersonen(string $organisationId): JSONResponse { try { // Get object service. - $objectService = $this->container->get('OCA\OpenRegister\Service\ObjectService'); // Search for contactpersonen belonging to this organisation. // Use a more generic search that doesn't require specific register/schema. @@ -212,7 +215,7 @@ public function getContactpersonen(string $organisationId): JSONResponse { // Let ObjectService resolve the schema. ]; - $contactpersonen = $objectService->searchObjectsPaginated($searchParams); + $contactpersonen = $this->objectService->searchObjectsPaginated($searchParams); // Enhance with user information. // @@ -308,8 +311,7 @@ private function checkOrganisationReadPermission(\OCP\IUser $currentUser, string $callerOrgUuid = null; try { - $objectService = $this->container->get('OCA\OpenRegister\Service\ObjectService'); - $callerOrgUuid = $this->resolveContactOrganisation(objectService: $objectService, username: $currentUser->getUID()); + $callerOrgUuid = $this->resolveContactOrganisation(objectService: $this->objectService, username: $currentUser->getUID()); } catch (\Exception $e) { $this->logger->warning( 'ContactpersonenController: could not resolve the caller organisation, denying contact read', @@ -404,10 +406,9 @@ public function convertToUser(string $contactPersonId): JSONResponse { try { // Get object service. - $objectService = $this->container->get('OCA\OpenRegister\Service\ObjectService'); // Find the contactpersoon object — bind to current tenant. - $contactPersonObject = $objectService->find( + $contactPersonObject = $this->objectService->find( id: $contactPersonId, register: 'voorzieningen', schema: 'contactPerson', @@ -531,10 +532,24 @@ public function convertToUser(string $contactPersonId): JSONResponse { ] ); - // Save using MagicMapper directly to bypass schema validation. - // This avoids "Unresolved reference" errors when schema references can't be resolved. - $objectMapper = $this->container->get('OCA\OpenRegister\Db\MagicMapper'); - $objectMapper->update($contactPersonObject); + // Save WITHOUT schema validation, to avoid "Unresolved reference" + // errors when schema references cannot be resolved. + // + // This used to reach into OpenRegister's MagicMapper directly — its Db + // layer — which ADR-022 exists to prevent and which no leaf app can + // load in its own tests. The published contract already exposes the + // same capability as a flag, and ObjectService::saveObject() routes + // through that very mapper with register+schema, so the magic table is + // written exactly as before. + $this->objectService->saveObject( + object: $contactData, + register: $registerId, + schema: $schemaId, + uuid: $contactPersonObject->getUuid(), + silent: true, + silent: true, + _validation: false + ); $this->logger->info( 'ContactpersonenController: Updated contactpersoon with username', @@ -942,10 +957,8 @@ private function checkGroupUpdatePermission(\OCP\IUser $currentUser, string $use */ private function verifyCrossTenantScope(\OCP\IUser $currentUser, string $username): ?JSONResponse { try { - $objectService = $this->container->get('OCA\OpenRegister\Service\ObjectService'); - - $targetOrgUuid = $this->resolveContactOrganisation(objectService: $objectService, username: $username); - $callerOrgUuid = $this->resolveContactOrganisation(objectService: $objectService, username: $currentUser->getUID()); + $targetOrgUuid = $this->resolveContactOrganisation(objectService: $this->objectService, username: $username); + $callerOrgUuid = $this->resolveContactOrganisation(objectService: $this->objectService, username: $currentUser->getUID()); if ($targetOrgUuid !== null && $callerOrgUuid !== null && $targetOrgUuid !== $callerOrgUuid) { $this->logger->warning( @@ -988,6 +1001,9 @@ private function verifyCrossTenantScope(\OCP\IUser $currentUser, string $usernam * @spec openspec/changes/method-decomposition/tasks.md#task-5 */ private function resolveContactOrganisation(object $objectService, string $username): ?string { + // development's side on both counts: this method TAKES $objectService as a + // parameter (my dangling-reference pass wrongly made it a property read), + // and the schema slug was renamed contactpersoon -> contactPerson there. $results = $objectService->searchObjectsPaginated( ['username' => $username, '_limit' => 1, '_schema' => 'contactPerson'] ); @@ -1203,8 +1219,7 @@ public function getUserInfo(string $contactPersonId): JSONResponse { } try { - $objectService = $this->container->get('OCA\OpenRegister\Service\ObjectService'); - $contactObject = $objectService->find( + $contactObject = $this->objectService->find( id: $contactPersonId, register: 'voorzieningen', schema: 'contactPerson' @@ -1597,10 +1612,8 @@ public function getMe(): JSONResponse { // Get organisation data from OpenRegister. try { - $organisationService = $this->container->get('OCA\OpenRegister\Service\OrganisationService'); - // Get active organisation. - $activeOrg = $organisationService->getActiveOrganisation(); + $activeOrg = $this->organisationService->getActiveOrganisation(); if ($activeOrg !== null) { $response['organisations']['active'] = [ 'uuid' => $activeOrg->getUuid(), @@ -1611,7 +1624,7 @@ public function getMe(): JSONResponse { } // Get all user organisations. - $userOrgs = $organisationService->getUserOrganisations(); + $userOrgs = $this->organisationService->getUserOrganisations(); foreach ($userOrgs as $org) { $response['organisations']['all'][] = [ 'uuid' => $org->getUuid(), @@ -1728,15 +1741,13 @@ private function enrichMeWithContactPersonData( string $userEmail, ): void { try { - $objectService = $this->container->get('OCA\OpenRegister\Service\ObjectService'); - $searchParams = [ 'username' => $userId, '_limit' => 1, '_schema' => 'contactPerson', ]; - $contactpersonen = $objectService->searchObjectsPaginated($searchParams); + $contactpersonen = $this->objectService->searchObjectsPaginated($searchParams); if (empty($contactpersonen['results']) === false) { $contactPerson = $contactpersonen['results'][0]; diff --git a/lib/Controller/OrganisationMembersController.php b/lib/Controller/OrganisationMembersController.php index 92ebd0aa..6e368c29 100644 --- a/lib/Controller/OrganisationMembersController.php +++ b/lib/Controller/OrganisationMembersController.php @@ -52,8 +52,8 @@ use OCP\IRequest; use OCP\IUserManager; use OCP\IUserSession; -use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; +use OCA\OpenRegister\Service\OrganisationService; /** * Beheerder-gated grant/revoke of organisation membership for an existing @@ -77,7 +77,6 @@ class OrganisationMembersController extends Controller { * @param IUserSession $userSession The user session (auth guard). * @param IGroupManager $groupManager Group membership (beheerder guard). * @param IUserManager $userManager User lookup (existing-user-only guard). - * @param ContainerInterface $container DI container, used to reach OpenRegister's * `OrganisationService` without a hard compile-time * dependency on another app's class. * @param LoggerInterface $logger Logger. @@ -87,8 +86,8 @@ public function __construct( private readonly IUserSession $userSession, private readonly IGroupManager $groupManager, private readonly IUserManager $userManager, - private readonly ContainerInterface $container, private readonly LoggerInterface $logger, + private readonly OrganisationService $organisationService, ) { parent::__construct(appName: Application::APP_ID, request: $request); }//end __construct() @@ -266,6 +265,6 @@ private function authorizeMaintainer(string $organisationUuid): ?JSONResponse { * @throws \Throwable When OpenRegister is unavailable. */ private function getOrganisationService(): \OCA\OpenRegister\Service\OrganisationService { - return $this->container->get('OCA\OpenRegister\Service\OrganisationService'); + return $this->organisationService; }//end getOrganisationService() }//end class diff --git a/lib/Controller/SettingsController.php b/lib/Controller/SettingsController.php index 6f203ad1..e3eb3e89 100644 --- a/lib/Controller/SettingsController.php +++ b/lib/Controller/SettingsController.php @@ -25,7 +25,7 @@ namespace OCA\SoftwareCatalog\Controller; use OCA\OpenRegister\Service\ConfigurationService; -use OCA\OpenRegister\Service\ObjectService; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCA\SoftwareCatalog\Service\ArchiMateService; use OCA\SoftwareCatalog\Service\EolSyncService; use OCA\SoftwareCatalog\Service\OrganizationSyncService; @@ -64,7 +64,7 @@ class SettingsController extends Controller { /** * The OpenRegister object service. * - * @var ObjectService|null The OpenRegister object service. + * @var ObjectServiceInterface|null The OpenRegister object service. */ private $objectService; @@ -109,11 +109,11 @@ public function __construct( /** * Attempts to retrieve the OpenRegister service from the container. * - * @return ObjectService|null The OpenRegister service if available, null otherwise. + * @return ObjectServiceInterface|null The OpenRegister service if available, null otherwise. * @throws RuntimeException If the service is not available. * @spec openspec/specs/settings-admin-controller/spec.md */ - public function getObjectService(): ?ObjectService { + public function getObjectService(): ?ObjectServiceInterface { if (in_array(needle: 'openregister', haystack: $this->appManager->getInstalledApps()) === true) { $this->objectService = $this->container->get('OCA\OpenRegister\Service\ObjectService'); return $this->objectService; diff --git a/lib/EventListener/UserProfileUpdatedEventListener.php b/lib/EventListener/UserProfileUpdatedEventListener.php index 54ecc1c7..2735bbc6 100644 --- a/lib/EventListener/UserProfileUpdatedEventListener.php +++ b/lib/EventListener/UserProfileUpdatedEventListener.php @@ -25,6 +25,10 @@ use OCP\EventDispatcher\IEventListener; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; +use OCA\OpenRegister\Contract\ObjectServiceInterface; +use OCA\OpenRegister\Db\SchemaMapper; +use OCA\OpenRegister\Db\RegisterMapper; +use OCA\OpenRegister\Service\Object\SaveObject\MetadataHydrationHandler; /** * Syncs user profile changes to the corresponding contactpersoon object. @@ -56,6 +60,10 @@ class UserProfileUpdatedEventListener implements IEventListener { */ public function __construct( private readonly ContainerInterface $container, + private readonly ObjectServiceInterface $objectService, + private readonly SchemaMapper $schemaMapper, + private readonly RegisterMapper $registerMapper, + private readonly MetadataHydrationHandler $metadataHydrationHandler, ) { }//end __construct() @@ -128,7 +136,6 @@ public function handle(Event $event): void { * @spec openspec/specs/method-decomposition/spec.md */ private function syncToContactPerson(UserProfileUpdatedEvent $event, LoggerInterface $logger): void { - $objectService = $this->container->get('OCA\OpenRegister\Service\ObjectService'); $settingsService = $this->container->get(SettingsService::class); $voorzieningenConfig = $settingsService->getVoorzieningenConfig(); @@ -149,7 +156,7 @@ private function syncToContactPerson(UserProfileUpdatedEvent $event, LoggerInter ]; $contactPerson = $this->findContactPerson( - objectService: $objectService, + objectService: $this->objectService, selfQuery: $selfQuery, userId: $userId, event: $event, @@ -283,15 +290,11 @@ private function persistContactPersonPatch( int $schema, LoggerInterface $logger, ): void { - $schemaMapper = $this->container->get('OCA\OpenRegister\Db\SchemaMapper'); - $registerMapper = $this->container->get('OCA\OpenRegister\Db\RegisterMapper'); - $metaHydrationHandler = $this->container->get('OCA\OpenRegister\Service\Object\SaveObject\MetadataHydrationHandler'); - $schemaEntity = null; $registerEntity = null; try { - $schemaEntity = $schemaMapper->find(id: $schema, _rbac: false, _multitenancy: false); - $registerEntity = $registerMapper->find(id: $register, _rbac: false, _multitenancy: false); + $schemaEntity = $this->schemaMapper->find(id: $schema, _rbac: false, _multitenancy: false); + $registerEntity = $this->registerMapper->find(id: $register, _rbac: false, _multitenancy: false); } catch (\Exception $e) { $logger->warning( '[UserProfileUpdatedEventListener] Could not load schema/register entities for _name hydration', @@ -302,7 +305,7 @@ private function persistContactPersonPatch( } if ($schemaEntity !== null) { - $metaHydrationHandler->hydrateObjectMetadata(entity: $contactPerson, schema: $schemaEntity); + $this->metadataHydrationHandler->hydrateObjectMetadata(entity: $contactPerson, schema: $schemaEntity); $logger->debug( '[UserProfileUpdatedEventListener] Regenerated _name metadata', [ @@ -311,10 +314,21 @@ private function persistContactPersonPatch( ); } - // Pass register and schema so the magic mapper route is triggered and the - // per-schema magic table is updated (not just the blob table). - $objectMapper = $this->container->get('OCA\OpenRegister\Db\MagicMapper'); - $objectMapper->update(entity: $contactPerson, register: $registerEntity, schema: $schemaEntity); + // Persist through the published contract rather than OpenRegister's Db + // layer. The comment this replaces worried that a plain save would touch + // "just the blob table" — it does not: ObjectService::saveObject() calls + // metaHydrationHandler->hydrateObjectMetadata() and then + // objectEntityMapper->update(entity:, register:, schema:), which IS the + // magic-mapper route. This listener was hand-rolling OpenRegister's own + // save pipeline, one layer too deep. + $this->objectService->saveObject( + object: $contactPerson->getObject(), + register: $contactPerson->getRegister(), + schema: $contactPerson->getSchema(), + uuid: $contactPerson->getUuid(), + silent: true, + _validation: false + ); }//end persistContactpersoonPatch() diff --git a/lib/Service/AanbodService.php b/lib/Service/AanbodService.php index cebbcee4..e2552288 100644 --- a/lib/Service/AanbodService.php +++ b/lib/Service/AanbodService.php @@ -23,7 +23,7 @@ namespace OCA\SoftwareCatalog\Service; use Exception; -use OCA\OpenRegister\Service\ObjectService; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCP\App\IAppManager; use OCP\IAppConfig; use OCP\IUserSession; @@ -590,13 +590,13 @@ private function resolvePartyId(mixed $partyInfo): ?string { * an aanbod can be any of these types. Register/schema context is * required to find objects stored in magic tables. * - * @param ObjectService $objectService The OpenRegister object service + * @param ObjectServiceInterface $objectService The OpenRegister object service * @param string $aanbodId The UUID of the aanbod object * * @return \OCA\OpenRegister\Db\ObjectEntity|null The found object or null */ private function findAanbodObject( - ObjectService $objectService, + ObjectServiceInterface $objectService, string $aanbodId, ): ?\OCA\OpenRegister\Db\ObjectEntity { $voorzieningenConfig = $this->settingsService->getVoorzieningenConfig(); @@ -681,11 +681,11 @@ private function getCurrentOrganisation(): ?string { /** * Get ObjectService from OpenRegister app. * - * @return ObjectService The OpenRegister object service + * @return ObjectServiceInterface The OpenRegister object service * * @throws Exception When OpenRegister service is not available */ - private function getObjectService(): ObjectService { + private function getObjectService(): ObjectServiceInterface { if (in_array(needle: 'openregister', haystack: $this->appManager->getInstalledApps()) === false) { throw new Exception('OpenRegister app is not installed'); } @@ -747,14 +747,14 @@ private function addQueryFilters(array $baseQuery, array $options): array { * Looks up the organisation object by UUID, reads its type, and maps it * to the appropriate registeredBy value using TYPE_MAP. * - * @param ObjectService $objectService The OpenRegister object service + * @param ObjectServiceInterface $objectService The OpenRegister object service * @param array $objectData The object data to update * @param string $organisationUuid The UUID of the organisation to look up * * @return array The updated object data */ private function updateRegisteredBy( - ObjectService $objectService, + ObjectServiceInterface $objectService, array $objectData, string $organisationUuid, ): array { diff --git a/lib/Service/AangebodenGebruik/GebruikBulkHandler.php b/lib/Service/AangebodenGebruik/GebruikBulkHandler.php index 8f7e6a18..76dcf196 100644 --- a/lib/Service/AangebodenGebruik/GebruikBulkHandler.php +++ b/lib/Service/AangebodenGebruik/GebruikBulkHandler.php @@ -23,7 +23,7 @@ namespace OCA\SoftwareCatalog\Service\AangebodenGebruik; -use OCA\OpenRegister\Service\ObjectService; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use Psr\Log\LoggerInterface; /** @@ -38,13 +38,13 @@ class GebruikBulkHandler { /** * Constructor. * - * @param ObjectService $objectService The OpenRegister object service. + * @param ObjectServiceInterface $objectService The OpenRegister object service. * @param LoggerInterface $logger Logger instance. * * @spec openspec/changes/method-decomposition/tasks.md#task-7 */ public function __construct( - private readonly ObjectService $objectService, + private readonly ObjectServiceInterface $objectService, private readonly LoggerInterface $logger, ) { }//end __construct() diff --git a/lib/Service/AangebodenGebruik/GebruikStatusHandler.php b/lib/Service/AangebodenGebruik/GebruikStatusHandler.php index 9dad695b..25655a25 100644 --- a/lib/Service/AangebodenGebruik/GebruikStatusHandler.php +++ b/lib/Service/AangebodenGebruik/GebruikStatusHandler.php @@ -24,7 +24,7 @@ namespace OCA\SoftwareCatalog\Service\AangebodenGebruik; -use OCA\OpenRegister\Service\ObjectService; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use Psr\Log\LoggerInterface; /** @@ -39,14 +39,14 @@ class GebruikStatusHandler { /** * Constructor. * - * @param ObjectService $objectService The OpenRegister object service. + * @param ObjectServiceInterface $objectService The OpenRegister object service. * @param StatusTransitionValidator $validator Status transition validator. * @param LoggerInterface $logger Logger instance. * * @spec openspec/changes/method-decomposition/tasks.md#task-7 */ public function __construct( - private readonly ObjectService $objectService, + private readonly ObjectServiceInterface $objectService, private readonly StatusTransitionValidator $validator, private readonly LoggerInterface $logger, ) { diff --git a/lib/Service/AangebodenGebruikService.php b/lib/Service/AangebodenGebruikService.php index 79108205..de645da5 100644 --- a/lib/Service/AangebodenGebruikService.php +++ b/lib/Service/AangebodenGebruikService.php @@ -21,7 +21,7 @@ namespace OCA\SoftwareCatalog\Service; use Exception; -use OCA\OpenRegister\Service\ObjectService; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCP\App\IAppManager; use OCP\IAppConfig; use OCP\IUserSession; @@ -1046,13 +1046,13 @@ public function setGebruikSelfToActiveOrg(string $gebruikId, array $options = [] * either type. Register/schema context is required to find objects * stored in magic tables. * - * @param ObjectService $objectService The OpenRegister object service + * @param ObjectServiceInterface $objectService The OpenRegister object service * @param string $objectId The UUID of the object to find * * @return \OCA\OpenRegister\Db\ObjectEntity|null The found object or null */ private function findGebruikOrIntegration( - ObjectService $objectService, + ObjectServiceInterface $objectService, string $objectId, ): ?\OCA\OpenRegister\Db\ObjectEntity { $voorzieningenConfig = $this->settingsService->getVoorzieningenConfig(); @@ -1135,10 +1135,10 @@ private function getCurrentOrganisation(): ?string { /** * Get ObjectService from OpenRegister app * - * @return ObjectService The OpenRegister object service + * @return ObjectServiceInterface The OpenRegister object service * @throws Exception When OpenRegister service is not available */ - private function getObjectService(): ObjectService { + private function getObjectService(): ObjectServiceInterface { if (in_array(needle: 'openregister', haystack: $this->appManager->getInstalledApps()) === false) { throw new Exception('OpenRegister app is not installed'); } @@ -1241,7 +1241,7 @@ private function resolveVoorzieningenSchemaConfig(string $schemaKey, string $lab * * Uses ObjectService's buildSearchQuery() for proper query construction * - * @param ObjectService $objectService The OpenRegister object service + * @param ObjectServiceInterface $objectService The OpenRegister object service * @param string $registerId The register ID * @param string $schemaId The schema ID * @param array $options Query options (includes request parameters for buildSearchQuery) @@ -1252,7 +1252,7 @@ private function resolveVoorzieningenSchemaConfig(string $schemaKey, string $lab * @throws Exception When query fails */ private function getAllObjectsForSchema( - ObjectService $objectService, + ObjectServiceInterface $objectService, string $registerId, string $schemaId, array $options = [], @@ -1297,7 +1297,7 @@ private function getAllObjectsForSchema( /** * Get all applications/modules owned by an organization * - * @param ObjectService $objectService The OpenRegister object service + * @param ObjectServiceInterface $objectService The OpenRegister object service * @param string $organisationUuid The organization UUID * * @return array Array of application/module UUIDs @@ -1305,7 +1305,7 @@ private function getAllObjectsForSchema( * @throws Exception When query fails */ private function getApplicationsOwnedByOrganisation( - ObjectService $objectService, + ObjectServiceInterface $objectService, string $organisationUuid, ): array { try { @@ -1403,7 +1403,7 @@ private function getApplicationsOwnedByOrganisation( * * Uses ObjectService's buildSearchQuery() for proper query construction * - * @param ObjectService $objectService The OpenRegister object service + * @param ObjectServiceInterface $objectService The OpenRegister object service * @param string $registerId The register ID * @param string $schemaId The schema ID * @param string $relatedUuid The UUID to find relationships for @@ -1415,7 +1415,7 @@ private function getApplicationsOwnedByOrganisation( * @throws Exception When query fails */ private function getObjectsRelatedToUuid( - ObjectService $objectService, + ObjectServiceInterface $objectService, string $registerId, string $schemaId, string $relatedUuid, @@ -1463,14 +1463,14 @@ private function getObjectsRelatedToUuid( /** * Check if an organization owns a specific application/module * - * @param ObjectService $objectService The OpenRegister object service + * @param ObjectServiceInterface $objectService The OpenRegister object service * @param string $appUuid The application/module UUID * @param string $organisationUuid The organization UUID * * @return bool True if organization owns the application/module */ private function checkOrganisationOwnership( - ObjectService $objectService, + ObjectServiceInterface $objectService, string $appUuid, string $organisationUuid, ): bool { @@ -1532,14 +1532,14 @@ private function checkOrganisationOwnership( * Looks up the organisation object by UUID, reads its type, and maps it * to the appropriate registeredBy value using TYPE_MAP. * - * @param ObjectService $objectService The OpenRegister object service + * @param ObjectServiceInterface $objectService The OpenRegister object service * @param array $objectData The object data to update * @param string $organisationUuid The UUID of the organisation to look up * * @return array The updated object data */ private function updateRegisteredBy( - ObjectService $objectService, + ObjectServiceInterface $objectService, array $objectData, string $organisationUuid, ): array { diff --git a/lib/Service/ArchiMate/ArchiMateContext.php b/lib/Service/ArchiMate/ArchiMateContext.php index b1f11729..e31edf57 100644 --- a/lib/Service/ArchiMate/ArchiMateContext.php +++ b/lib/Service/ArchiMate/ArchiMateContext.php @@ -23,7 +23,7 @@ namespace OCA\SoftwareCatalog\Service\ArchiMate; -use OCA\OpenRegister\Service\ObjectService; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCA\SoftwareCatalog\Service\SettingsService; use Psr\Log\LoggerInterface; @@ -40,14 +40,14 @@ class ArchiMateContext { /** * Constructor. * - * @param ObjectService $objectService The OpenRegister object service. + * @param ObjectServiceInterface $objectService The OpenRegister object service. * @param SettingsService $settingsService The SoftwareCatalog settings service. * @param LoggerInterface $logger The application logger. * * @spec openspec/changes/method-decomposition/tasks.md#task-4 */ public function __construct( - public readonly ObjectService $objectService, + public readonly ObjectServiceInterface $objectService, public readonly SettingsService $settingsService, public readonly LoggerInterface $logger, ) { diff --git a/lib/Service/ArchiMateExportService.php b/lib/Service/ArchiMateExportService.php index f2ccbe41..a061ec4b 100644 --- a/lib/Service/ArchiMateExportService.php +++ b/lib/Service/ArchiMateExportService.php @@ -796,7 +796,7 @@ private function addObjectToFolder(\SimpleXMLElement $folder, array $object, str * requires both register AND schema in the query. Without schema, the query * falls back to the generic objects table (which is empty for magic-table registers). * - * @param \OCA\OpenRegister\Service\ObjectService $objectService OpenRegister ObjectService. + * @param \OCA\OpenRegister\Contract\ObjectServiceInterface $objectService OpenRegister ObjectService. * @param int $registerId AMEF register ID. * @param array $schemaIdMap Mapping of schema IDs to schema types. * @@ -806,7 +806,7 @@ private function addObjectToFolder(\SimpleXMLElement $folder, array $object, str * @spec openspec/specs/archimate-export/spec.md */ public function getObjectsFromDatabase( - \OCA\OpenRegister\Service\ObjectService $objectService, + \OCA\OpenRegister\Contract\ObjectServiceInterface $objectService, int $registerId, array $schemaIdMap = [], ): array { @@ -940,7 +940,7 @@ public function addPropertyDefinitionsToXml(\SimpleXMLElement $xml, array $prope * 3. Direct XML generation without intermediate arrays * 4. No JSON serialization overhead * - * @param \OCA\OpenRegister\Service\ObjectService $objectService OpenRegister ObjectService. + * @param \OCA\OpenRegister\Contract\ObjectServiceInterface $objectService OpenRegister ObjectService. * @param int $registerId AMEF register ID. * @param array $schemaIdMap Schema IDs to types mapping. * @param string|null $organization Organization filter. @@ -949,7 +949,7 @@ public function addPropertyDefinitionsToXml(\SimpleXMLElement $xml, array $prope * @spec openspec/specs/archimate-export/spec.md */ public function exportArchiMateXml( - \OCA\OpenRegister\Service\ObjectService $objectService, + \OCA\OpenRegister\Contract\ObjectServiceInterface $objectService, int $registerId, array $schemaIdMap, ?string $organization = null, @@ -2384,7 +2384,7 @@ private function validateTextContentNormalized(\SimpleXMLElement $xml): void { * referentiecomponenten, copies views with applications plotted inside, and * adds SWC-specific organization folders. * - * @param \OCA\OpenRegister\Service\ObjectService $objectService The object service. + * @param \OCA\OpenRegister\Contract\ObjectServiceInterface $objectService The object service. * @param int $registerId AMEF register ID. * @param array $schemaIdMap Schema ID to type map. * @param string $orgName Organization name. @@ -2398,7 +2398,7 @@ private function validateTextContentNormalized(\SimpleXMLElement $xml): void { * @spec openspec/specs/archimate-export/spec.md */ public function exportOrganizationArchiMateXml( - \OCA\OpenRegister\Service\ObjectService $objectService, + \OCA\OpenRegister\Contract\ObjectServiceInterface $objectService, int $registerId, array $schemaIdMap, string $orgName, diff --git a/lib/Service/ArchiMateImportService.php b/lib/Service/ArchiMateImportService.php index 91cd789d..c7d5fb88 100644 --- a/lib/Service/ArchiMateImportService.php +++ b/lib/Service/ArchiMateImportService.php @@ -20,6 +20,7 @@ namespace OCA\SoftwareCatalog\Service; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCA\OpenRegister\Service\ObjectService; use OCA\OpenRegister\Service\OrganisationService; use OCP\App\IAppManager; @@ -1546,12 +1547,12 @@ private function fixStandaardVersieUuids(int $registerId): void { * Lets ObjectService handle all batching, throttling, and optimization internally * * @param array $objects Array of objects to save - * @param ObjectService $objectService ObjectService instance + * @param ObjectServiceInterface $objectService ObjectService instance * @param int $registerId Register ID * * @return array Array of saved objects */ - private function saveObjectsDirectToService(array $objects, ObjectService $objectService, int $registerId): array { + private function saveObjectsDirectToService(array $objects, ObjectServiceInterface $objectService, int $registerId): array { try { // GROUP BY SCHEMA: For magic mapping support, save objects schema by schema. // This ensures each batch has a single schema so UnifiedObjectMapper can route to the correct table. @@ -1654,12 +1655,12 @@ private function saveObjectsDirectToService(array $objects, ObjectService $objec * Save objects in parallel batches for maximum performance (DEPRECATED) * * @param array $objects Array of objects to save - * @param ObjectService $objectService ObjectService instance + * @param ObjectServiceInterface $objectService ObjectService instance * @param int $registerId Register ID * * @return array Array of saved objects */ - private function saveObjectsInParallelBatches(array $objects, ObjectService $objectService, int $registerId): array { + private function saveObjectsInParallelBatches(array $objects, ObjectServiceInterface $objectService, int $registerId): array { $batchSize = self::PERFORMANCE_OPTIMIZATIONS['batch_size']; $parallelBatches = self::PERFORMANCE_OPTIMIZATIONS['parallel_batches']; @@ -1769,12 +1770,12 @@ private function saveObjectsInParallelBatches(array $objects, ObjectService $obj * Save objects in a single batch (fallback method) * * @param array $objects Array of objects to save - * @param ObjectService $objectService ObjectService instance + * @param ObjectServiceInterface $objectService ObjectService instance * @param int $registerId Register ID * * @return array Array of saved objects */ - private function saveObjectsInSingleBatch(array $objects, ObjectService $objectService, int $registerId): array { + private function saveObjectsInSingleBatch(array $objects, ObjectServiceInterface $objectService, int $registerId): array { // Using single batch processing. // Disable RBAC for bulk import when the performance optimisation flag is set. if (self::PERFORMANCE_OPTIMIZATIONS['disable_rbac'] === true) { @@ -1812,9 +1813,9 @@ private function saveObjectsInSingleBatch(array $objects, ObjectService $objectS /** * Get ObjectService from container * - * @return ObjectService|null ObjectService instance or null if not available + * @return ObjectServiceInterface|null ObjectService instance or null if not available */ - private function getObjectService(): ?ObjectService { + private function getObjectService(): ?ObjectServiceInterface { if ($this->appManager->isInstalled(appId: 'openregister') === false) { return null; } diff --git a/lib/Service/ArchiMateService.php b/lib/Service/ArchiMateService.php index 0f2cd3dd..1a123163 100644 --- a/lib/Service/ArchiMateService.php +++ b/lib/Service/ArchiMateService.php @@ -21,6 +21,7 @@ namespace OCA\SoftwareCatalog\Service; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCA\OpenRegister\Service\ObjectService; use OCP\App\IAppManager; use OCP\Files\IRootFolder; @@ -1076,12 +1077,12 @@ private function saveObjectsToDatabase(array $objects): array { * Save objects in parallel batches for maximum performance * * @param array $objects Array of objects to save - * @param ObjectService $objectService ObjectService instance + * @param ObjectServiceInterface $objectService ObjectService instance * @param int $registerId Register ID * * @return array Array of saved objects */ - private function saveObjectsInParallelBatches(array $objects, ObjectService $objectService, int $registerId): array { + private function saveObjectsInParallelBatches(array $objects, ObjectServiceInterface $objectService, int $registerId): array { $batchSize = self::PERFORMANCE_OPTIMIZATIONS['batch_size']; $parallelBatches = self::PERFORMANCE_OPTIMIZATIONS['parallel_batches']; @@ -1195,12 +1196,12 @@ private function saveObjectsInParallelBatches(array $objects, ObjectService $obj * Save objects in a single batch (fallback method) * * @param array $objects Array of objects to save - * @param ObjectService $objectService ObjectService instance + * @param ObjectServiceInterface $objectService ObjectService instance * @param int $registerId Register ID * * @return array Array of saved objects */ - private function saveObjectsInSingleBatch(array $objects, ObjectService $objectService, int $registerId): array { + private function saveObjectsInSingleBatch(array $objects, ObjectServiceInterface $objectService, int $registerId): array { $this->logger->info( 'Using single batch processing', [ @@ -1281,9 +1282,9 @@ private function saveObjectsInSingleBatch(array $objects, ObjectService $objectS /** * Get ObjectService from container * - * @return ObjectService|null ObjectService instance or null if not available + * @return ObjectServiceInterface|null ObjectService instance or null if not available */ - private function getObjectService(): ?ObjectService { + private function getObjectService(): ?ObjectServiceInterface { if ($this->appManager->isInstalled(appId: 'openregister') === false) { return null; } diff --git a/lib/Service/ContactpersoonService.php b/lib/Service/ContactpersoonService.php index e6f08e0c..df7ae1b8 100644 --- a/lib/Service/ContactpersoonService.php +++ b/lib/Service/ContactpersoonService.php @@ -458,12 +458,28 @@ private function updateContactPersonUsername(object $contactPersonObject, string $contactData['username'] = $username; $contactPersonObject->setObject($contactData); - // FIX #434: Use MagicMapper directly instead of ObjectService::saveObject(). - // To avoid validation errors on the organisatie field (stored as UUID string but. - // Schema expects object type) and to avoid triggering ObjectUpdatedEvent cascades. - // That could interfere with the ongoing org activation process. - $objectMapper = $this->container->get('OCA\OpenRegister\Db\MagicMapper'); - $objectMapper->update($contactPersonObject); + // FIX #434, through the PUBLISHED contract instead of OpenRegister's Db + // layer. Both reasons the original gave are flags on saveObject(): + // + // _validation: false the organisatie field holds a UUID string where + // the schema expects an object + // silent: true no ObjectUpdatedEvent, so the cascade cannot + // interfere with an in-flight org activation + // + // saveObject() is not a lesser route: OpenRegister's SaveObject calls + // objectEntityMapper->update(entity:, register:, schema:) itself, which + // IS the magic-mapper path this used to reach for directly. + $objectService = $this->getObjectService(); + if ($objectService !== null) { + $objectService->saveObject( + object: $contactData, + register: $contactPersonObject->getRegister(), + schema: $contactPersonObject->getSchema(), + uuid: $contactPersonObject->getUuid(), + silent: true, + _validation: false + ); + } $this->logger->info( 'ContactpersoonService: Updated contactpersoon with username', @@ -659,9 +675,9 @@ private function handleRoleChanges(object $newContactPersonObject, object $oldCo /** * Gets the ObjectService instance * - * @return \OCA\OpenRegister\Service\ObjectService|null + * @return \OCA\OpenRegister\Contract\ObjectServiceInterface|null */ - private function getObjectService(): ?\OCA\OpenRegister\Service\ObjectService { + private function getObjectService(): ?\OCA\OpenRegister\Contract\ObjectServiceInterface { if ($this->appManager->isEnabledForUser('openregister') === false) { return null; } @@ -1197,11 +1213,34 @@ private function updateContactPersonObjectOwner(object $contactObject, string $u $contactObject->setOrganisation($organizationUuid); } - // FIX #434: Use MagicMapper directly instead of ObjectService::saveObject(). - // To avoid validation errors on the organisatie field (stored as UUID string but. - // Schema expects object type) and to avoid triggering ObjectUpdatedEvent cascades. - $objectMapper = $this->container->get('OCA\OpenRegister\Db\MagicMapper'); - $objectMapper->update($contactObject); + // FIX #434, through the PUBLISHED contract. Same two flags as the other + // site (_validation: false, silent: true), plus the two pieces of + // entity METADATA this call exists to set, which the payload API + // expresses differently: + // + // organisation travels in `@self`, which SaveObject reads and applies + // via setOrganisation() — behind an access check, so an + // organisation the caller may not use is refused rather + // than written, which the direct mapper call bypassed + // owner is NOT settable from the payload; SaveObject derives it + // from the acting user, so it is passed as `currentUser` + $objectService = $this->getObjectService(); + $userManager = $this->container->get('OCP\IUserManager'); + $actingUser = $userManager->get($userUID); + if ($objectService !== null && $actingUser !== null) { + $payload = $contactObject->getObject(); + $payload['@self'] = ['organisation' => $organizationUuid]; + + $objectService->saveObject( + object: $payload, + register: $contactObject->getRegister(), + schema: $contactObject->getSchema(), + uuid: $contactObject->getUuid(), + silent: true, + _validation: false, + currentUser: $actingUser + ); + } $this->logger->info( 'ContactpersoonService: Successfully updated contactpersoon object owner and organisation', diff --git a/lib/Service/ContractApprovalService.php b/lib/Service/ContractApprovalService.php index 67ed09e2..f1d13601 100644 --- a/lib/Service/ContractApprovalService.php +++ b/lib/Service/ContractApprovalService.php @@ -37,6 +37,7 @@ namespace OCA\SoftwareCatalog\Service; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCA\OpenRegister\Service\ObjectService; use OCP\EventDispatcher\IEventDispatcher; use Psr\Container\ContainerInterface; @@ -565,11 +566,11 @@ private function persistContract($contract, array $data): void { /** * Lazily resolve the OpenRegister ObjectService. * - * @return ObjectService|null The service, or null when OpenRegister is absent. + * @return ObjectServiceInterface|null The service, or null when OpenRegister is absent. * * @spec openspec/specs/contract-decision-delegation/spec.md */ - private function getObjectService(): ?ObjectService { + private function getObjectService(): ?ObjectServiceInterface { try { $service = $this->container->get('OCA\OpenRegister\Service\ObjectService'); if ($service instanceof ObjectService) { diff --git a/lib/Service/ContractStatusService.php b/lib/Service/ContractStatusService.php index 04fc5cb1..7d790128 100644 --- a/lib/Service/ContractStatusService.php +++ b/lib/Service/ContractStatusService.php @@ -27,6 +27,7 @@ namespace OCA\SoftwareCatalog\Service; use DateTimeImmutable; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCA\OpenRegister\Service\ObjectService; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; @@ -182,11 +183,11 @@ public function expirePastContracts(?DateTimeImmutable $now = null): int { /** * Lazily resolve the OpenRegister ObjectService. * - * @return ObjectService|null The service, or null when OpenRegister is absent. + * @return ObjectServiceInterface|null The service, or null when OpenRegister is absent. * * @spec openspec/specs/contract-administration/spec.md */ - private function getObjectService(): ?ObjectService { + private function getObjectService(): ?ObjectServiceInterface { try { $service = $this->container->get('OCA\OpenRegister\Service\ObjectService'); if ($service instanceof ObjectService) { diff --git a/lib/Service/EolSyncService.php b/lib/Service/EolSyncService.php index 7dcb21c2..8055899a 100644 --- a/lib/Service/EolSyncService.php +++ b/lib/Service/EolSyncService.php @@ -33,7 +33,7 @@ namespace OCA\SoftwareCatalog\Service; -use OCA\OpenRegister\Service\ObjectService; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCP\AppFramework\Utility\ITimeFactory; use Psr\Log\LoggerInterface; @@ -236,12 +236,12 @@ public function run(): array { * on the given `ObjectService` context. Returns false (never throws) * when the register or either schema cannot be found. * - * @param ObjectService $objectService The OpenRegister object service. + * @param ObjectServiceInterface $objectService The OpenRegister object service. * @param array $config The EOL sync configuration. * * @return bool True when the register/schemas resolved successfully. */ - private function resolveEolContext(ObjectService $objectService, array $config): bool { + private function resolveEolContext(ObjectServiceInterface $objectService, array $config): bool { try { $objectService->setRegister($config['register']); $objectService->setSchema($config['productSchema']); @@ -270,13 +270,13 @@ private function resolveEolContext(ObjectService $objectService, array $config): * write only happen for mapped modules (design.md non-functional * performance note). * - * @param ObjectService $objectService The OpenRegister object service. + * @param ObjectServiceInterface $objectService The OpenRegister object service. * @param int $moduleRegisterId The module register id. * @param int $moduleSchemaId The module schema id. * * @return array The mapped module rows (normalised arrays). */ - private function findMappedModules(ObjectService $objectService, int $moduleRegisterId, int $moduleSchemaId): array { + private function findMappedModules(ObjectServiceInterface $objectService, int $moduleRegisterId, int $moduleSchemaId): array { $query = [ '@self' => [ 'schema' => $moduleSchemaId, @@ -308,13 +308,13 @@ private function findMappedModules(ObjectService $objectService, int $moduleRegi * match — matching must never cross into another product's cycles * (design.md Decision 2 mitigation). * - * @param ObjectService $objectService The OpenRegister object service. + * @param ObjectServiceInterface $objectService The OpenRegister object service. * @param array $config The EOL sync configuration. * @param string $productSlug The mapped module's `eolProductSlug`. * * @return array The matching `eolCycle` rows (normalised arrays). */ - private function fetchCycles(ObjectService $objectService, array $config, string $productSlug): array { + private function fetchCycles(ObjectServiceInterface $objectService, array $config, string $productSlug): array { try { $objectService->setRegister($config['register']); $objectService->setSchema($config['cycleSchema']); @@ -352,7 +352,7 @@ private function fetchCycles(ObjectService $objectService, array $config, string /** * Fetch the `moduleVersie` rows belonging to one module. * - * @param ObjectService $objectService The OpenRegister object service. + * @param ObjectServiceInterface $objectService The OpenRegister object service. * @param int $moduleRegisterId The (softwarecatalog) module register id. * @param int $versionSchemaId The moduleVersie schema id. * @param string $moduleUuid The owning module's uuid. @@ -360,7 +360,7 @@ private function fetchCycles(ObjectService $objectService, array $config, string * @return array The module's `moduleVersie` rows (normalised arrays). */ private function fetchModuleVersions( - ObjectService $objectService, + ObjectServiceInterface $objectService, int $moduleRegisterId, int $versionSchemaId, string $moduleUuid, @@ -397,7 +397,7 @@ private function fetchModuleVersions( * existing uuid is supplied so this is an update, never a duplicate * create. * - * @param ObjectService $objectService The OpenRegister object service. + * @param ObjectServiceInterface $objectService The OpenRegister object service. * @param int $moduleRegisterId The module register id. * @param int $versionSchemaId The moduleVersie schema id. * @param array $stampedVersion The complete stamped `moduleVersie` object. @@ -407,7 +407,7 @@ private function fetchModuleVersions( * @spec openspec/specs/eol-feed-integration/spec.md#requirement-stamping-preserves-every-other-field-and-records-provenance */ private function saveStampedVersion( - ObjectService $objectService, + ObjectServiceInterface $objectService, int $moduleRegisterId, int $versionSchemaId, array $stampedVersion, diff --git a/lib/Service/FacetService.php b/lib/Service/FacetService.php index 01c79ba2..99e56158 100644 --- a/lib/Service/FacetService.php +++ b/lib/Service/FacetService.php @@ -26,6 +26,7 @@ namespace OCA\SoftwareCatalog\Service; use InvalidArgumentException; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCA\OpenRegister\Service\ObjectService; use OCP\ICache; use OCP\ICacheFactory; @@ -226,7 +227,7 @@ private function assertSupportedSchema(string $schema): void { * values, compute disjunctive counts, and assemble the response * (including `_meta.matchedObjectIds` for the frontend's list narrowing). * - * @param ObjectService $objectService OpenRegister object service. + * @param ObjectServiceInterface $objectService OpenRegister object service. * @param string $schema `module` or `dienst`. * @param array $normalizedFilters Normalized selected filters. * @param string|null $normalizedSearch Normalized free-text query. @@ -237,7 +238,7 @@ private function assertSupportedSchema(string $schema): void { * matchedObjectIds: string[]}} */ private function computeFacetsForRequest( - ObjectService $objectService, + ObjectServiceInterface $objectService, string $schema, array $normalizedFilters, ?string $normalizedSearch, @@ -386,7 +387,7 @@ private function buildCacheKey(string $schema, array $filters, ?string $search, * documented `MAX_BASE_PAGES` ceiling instead of ever issuing a single * unbounded `searchObjects()` call. * - * @param ObjectService $objectService OpenRegister object service. + * @param ObjectServiceInterface $objectService OpenRegister object service. * @param string $schema `module` or `dienst`. * @param string|null $search Free-text query. * @param string|null $organization Organisation override. @@ -396,7 +397,7 @@ private function buildCacheKey(string $schema, array $filters, ?string $search, * @spec openspec/specs/gemma-faceted-search/spec.md#requirement-facet-aggregation-queries-must-be-bounded * @spec openspec/specs/gemma-faceted-search/spec.md#requirement-facet-counts-must-respect-the-callers-rbactenant-context */ - private function fetchBaseObjects(ObjectService $objectService, string $schema, ?string $search, ?string $organization): array { + private function fetchBaseObjects(ObjectServiceInterface $objectService, string $schema, ?string $search, ?string $organization): array { $voorzieningenConfig = $this->settingsService->getVoorzieningenConfig(); $registerId = $voorzieningenConfig['register'] ?? null; // NOT `$schema . '_schema'`: the slugs are English now and the stored @@ -522,13 +523,13 @@ private function normalizeObject(mixed $object): array { * links are only transitive via `dienst.modules` — the linked module objects * are resolved with a single bounded batch lookup. * - * @param ObjectService $objectService OpenRegister object service. + * @param ObjectServiceInterface $objectService OpenRegister object service. * @param string $schema `module` or `dienst`. * @param array $baseObjects The candidate objects from `fetchBaseObjects()`. * * @return array> Object id => list of module objects. */ - private function resolveModulesPerObject(ObjectService $objectService, string $schema, array $baseObjects): array { + private function resolveModulesPerObject(ObjectServiceInterface $objectService, string $schema, array $baseObjects): array { $modulesByObjectId = []; if ($schema === 'module') { @@ -576,14 +577,14 @@ private function resolveModulesPerObject(ObjectService $objectService, string $s * Batch-fetch module objects by their OpenRegister object id, bounded by an * explicit `_limit`. * - * @param ObjectService $objectService OpenRegister object service. + * @param ObjectServiceInterface $objectService OpenRegister object service. * @param array $identifiers Distinct module object identifiers to resolve. * * @return array Module id => module object. * * @spec openspec/specs/gemma-faceted-search/spec.md#requirement-facet-aggregation-queries-must-be-bounded */ - private function fetchModulesByIdentifiers(ObjectService $objectService, array $identifiers): array { + private function fetchModulesByIdentifiers(ObjectServiceInterface $objectService, array $identifiers): array { if (empty($identifiers) === true) { return []; } @@ -1111,9 +1112,9 @@ private function getCurrentOrganisation(): ?string { /** * Get ObjectService from the container. * - * @return ObjectService|null ObjectService instance or null if not available. + * @return ObjectServiceInterface|null ObjectService instance or null if not available. */ - private function getObjectService(): ?ObjectService { + private function getObjectService(): ?ObjectServiceInterface { try { return $this->container->get(ObjectService::class); } catch (\Exception $e) { diff --git a/lib/Service/GebruikService.php b/lib/Service/GebruikService.php index 21909b8e..24cb777b 100644 --- a/lib/Service/GebruikService.php +++ b/lib/Service/GebruikService.php @@ -17,7 +17,7 @@ namespace OCA\SoftwareCatalog\Service; use Exception; -use OCA\OpenRegister\Service\ObjectService; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCP\App\IAppManager; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; @@ -101,11 +101,11 @@ private function getGebruiksConfiguration(): array { /** * Get ObjectService from OpenRegister app. * - * @return ObjectService The OpenRegister object service. + * @return ObjectServiceInterface The OpenRegister object service. * * @throws Exception When OpenRegister service is not available. */ - private function getObjectService(): ObjectService { + private function getObjectService(): ObjectServiceInterface { if (in_array('openregister', $this->appManager->getInstalledApps()) === false) { throw new Exception('OpenRegister app is not installed'); } diff --git a/lib/Service/GebruikSyncService.php b/lib/Service/GebruikSyncService.php index 2a95089a..d5778c53 100644 --- a/lib/Service/GebruikSyncService.php +++ b/lib/Service/GebruikSyncService.php @@ -29,6 +29,7 @@ use OCA\OpenRegister\Db\ObjectEntity; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; +use OCA\OpenRegister\Contract\ObjectServiceInterface; /** * Service for synchronizing and processing Gebruik (Usage) objects. @@ -86,6 +87,7 @@ public function __construct( LoggerInterface $logger, SettingsService $settingsService, ContainerInterface $container, + private readonly ObjectServiceInterface $objectService, ) { $this->logger = $logger; $this->settingsService = $settingsService; @@ -324,7 +326,6 @@ private function processAmefElements(ObjectEntity $gebruikObject): array { * @return array Array of found ObjectEntity objects. */ private function searchAmefElementsByIds(array $ids, string $register, string $schema): array { - $objectService = $this->container->get('OCA\OpenRegister\Service\ObjectService'); $foundElements = []; foreach ($ids as $id) { @@ -340,7 +341,7 @@ private function searchAmefElementsByIds(array $ids, string $register, string $s '_limit' => 5, ]; - $elements = $objectService->searchObjects($query); + $elements = $this->objectService->searchObjects($query); $foundElements = array_merge($foundElements, $elements); } catch (Exception $e) { $this->logger->warning( @@ -515,8 +516,6 @@ private function resolveLatestEligibleStatus(array $statusDates, string $gebruik */ private function updateGebruikObject(ObjectEntity $gebruikObject, array $updatedData): void { try { - $objectService = $this->container->get('OCA\OpenRegister\Service\ObjectService'); - // Get voorzieningenConfig to find the correct register and schema. $voorzieningenConfig = $this->settingsService->getVoorzieningenConfig(); $register = $voorzieningenConfig['register'] ?? ''; @@ -527,7 +526,7 @@ private function updateGebruikObject(ObjectEntity $gebruikObject, array $updated } // Update the object. - $objectService->saveObject( + $this->objectService->saveObject( object: $updatedData, register: (int)$register, schema: (int)$gebruikSchema, diff --git a/lib/Service/MergeOrganisatieService.php b/lib/Service/MergeOrganisatieService.php index 4be5c24f..b9200008 100644 --- a/lib/Service/MergeOrganisatieService.php +++ b/lib/Service/MergeOrganisatieService.php @@ -62,7 +62,7 @@ namespace OCA\SoftwareCatalog\Service; -use OCA\OpenRegister\Service\ObjectService; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCA\SoftwareCatalog\Service\SoftwareCatalogue\OrganizationHandler; use OCP\App\IAppManager; use OCP\EventDispatcher\IEventDispatcher; @@ -806,9 +806,9 @@ private function findAllForType(string $objectType): array { /** * Gets the OpenRegister ObjectService if available. * - * @return ObjectService|null ObjectService instance or null when openregister is not installed. + * @return ObjectServiceInterface|null ObjectService instance or null when openregister is not installed. */ - private function getObjectService(): ?ObjectService { + private function getObjectService(): ?ObjectServiceInterface { if (in_array(needle: 'openregister', haystack: $this->appManager->getInstalledApps()) === false) { return null; } diff --git a/lib/Service/ModuleComplianceService.php b/lib/Service/ModuleComplianceService.php index 5697f1bd..dfb181c8 100644 --- a/lib/Service/ModuleComplianceService.php +++ b/lib/Service/ModuleComplianceService.php @@ -21,7 +21,7 @@ namespace OCA\SoftwareCatalog\Service; -use OCA\OpenRegister\Service\ObjectService; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; @@ -846,9 +846,9 @@ public function bulkSyncModuleStandards(): array { /** * Get the object service * - * @return ObjectService|null The object service or null if not available + * @return ObjectServiceInterface|null The object service or null if not available */ - private function getObjectService(): ?ObjectService { + private function getObjectService(): ?ObjectServiceInterface { try { return $this->container->get('OCA\OpenRegister\Service\ObjectService'); } catch (\Exception $e) { diff --git a/lib/Service/ModuleRegistrationService.php b/lib/Service/ModuleRegistrationService.php index da43ea27..43606e83 100644 --- a/lib/Service/ModuleRegistrationService.php +++ b/lib/Service/ModuleRegistrationService.php @@ -21,7 +21,7 @@ namespace OCA\SoftwareCatalog\Service; -use OCA\OpenRegister\Service\ObjectService; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; @@ -273,9 +273,9 @@ private function updateModuleRegisteredBy(object $moduleObject, string $register /** * Get the object service from the DI container. * - * @return ObjectService|null The object service or null if not available + * @return ObjectServiceInterface|null The object service or null if not available */ - private function getObjectService(): ?ObjectService { + private function getObjectService(): ?ObjectServiceInterface { try { return $this->container->get('OCA\OpenRegister\Service\ObjectService'); } catch (\Exception $e) { diff --git a/lib/Service/ModuleVersionService.php b/lib/Service/ModuleVersionService.php index 29320d8b..4efb3d02 100644 --- a/lib/Service/ModuleVersionService.php +++ b/lib/Service/ModuleVersionService.php @@ -22,7 +22,7 @@ namespace OCA\SoftwareCatalog\Service; -use OCA\OpenRegister\Service\ObjectService; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; @@ -238,9 +238,9 @@ private function updateVersionRecord(array $context): void { /** * Get the object service from the DI container. * - * @return ObjectService|null The object service or null if not available + * @return ObjectServiceInterface|null The object service or null if not available */ - private function getObjectService(): ?ObjectService { + private function getObjectService(): ?ObjectServiceInterface { try { return $this->container->get('OCA\OpenRegister\Service\ObjectService'); } catch (\Exception $e) { diff --git a/lib/Service/OrganizationSyncService.php b/lib/Service/OrganizationSyncService.php index 0106c5ac..87c3228d 100644 --- a/lib/Service/OrganizationSyncService.php +++ b/lib/Service/OrganizationSyncService.php @@ -20,12 +20,14 @@ namespace OCA\SoftwareCatalog\Service; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCA\OpenRegister\Service\ObjectService; use OCA\SoftwareCatalog\Service\SoftwareCatalogue\ContactPersonHandler; use OCP\IAppConfig; use OCP\IDBConnection; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; +use OCA\OpenRegister\Db\OrganisationMapper; /** * Service for synchronizing organizations and contact persons. @@ -130,6 +132,8 @@ public function __construct( private IDBConnection $db, private readonly ContactPersonHandler $contactpersonHandler, ContainerInterface $container, + private readonly ObjectServiceInterface $objectService, + private readonly OrganisationMapper $organisationMapper, ) { $this->organisationService = $organisationService; $this->contactPersonService = $contactPersonService; @@ -380,8 +384,7 @@ public function performOrganizationsSync(int $batchSize = 50, int $maxExecutionS $rows = $qb->executeQuery()->fetchAll(); - $objectService = $this->container->get('OCA\OpenRegister\Service\ObjectService'); - if ($objectService instanceof ObjectService === false) { + if ($this->objectService instanceof ObjectService === false) { $this->logger->error('OrganizationSync: could not resolve ObjectService'); return $stats; } @@ -400,7 +403,7 @@ public function performOrganizationsSync(int $batchSize = 50, int $maxExecutionS } try { - $object = $objectService->find( + $object = $this->objectService->find( id: $row['uuid'], register: $register, schema: $organizationSchema, @@ -505,8 +508,7 @@ public function performContactSync(int $batchSize = 100, int $maxExecutionSecond $this->logger->info('ContactSync: processing ' . count($contacts) . ' contacts with existing NC accounts'); - $objectService = $this->container->get('OCA\OpenRegister\Service\ObjectService'); - if ($objectService instanceof ObjectService === false) { + if ($this->objectService instanceof ObjectService === false) { $this->logger->error('ContactSync: could not resolve ObjectService'); return $stats; } @@ -524,7 +526,7 @@ public function performContactSync(int $batchSize = 100, int $maxExecutionSecond } try { - $contactEntity = $objectService->find( + $contactEntity = $this->objectService->find( id: $contact['uuid'], register: $register, schema: $contactSchema, @@ -537,7 +539,7 @@ public function performContactSync(int $batchSize = 100, int $maxExecutionSecond // persisted record. The schema validation warning for a UUID-string value is // benign compared to a data-corruption window where the field is missing. $contactEntity->setObject($contactEntityObject); - $objectService->saveObject( + $this->objectService->saveObject( object: $contactEntity, register: $register, schema: $contactSchema, @@ -762,8 +764,6 @@ public function performFullSync(int $minutesBack = 10): array { */ private function getOrganisationObjectsByTimeWindow(string $register, string $organizationSchema, int $minutesBack): array { try { - $objectService = $this->container->get('OCA\OpenRegister\Service\ObjectService'); - // Build base query for register and schema. A sync tick may // genuinely need "all objects" (minutesBack <= 0) — bounded at a // documented safe ceiling rather than left unbounded. @@ -811,7 +811,7 @@ private function getOrganisationObjectsByTimeWindow(string $register, string $or } // Use searchObjects method for filtering. - $objects = $objectService->searchObjects(query: $query, _rbac: false, _multitenancy: false); + $objects = $this->objectService->searchObjects(query: $query, _rbac: false, _multitenancy: false); $this->logger->debug( 'OrganizationSyncService: Retrieved organisatie objects with searchObjects', @@ -949,8 +949,7 @@ private function ensureOrganisationEntity(object $organisationObject, array &$st // Fetch the complete object from the database to ensure we have all data. try { - $objectService = $this->container->get('OCA\OpenRegister\Service\ObjectService'); - $fullObject = $objectService->find( + $fullObject = $this->objectService->find( id: $organisationId, register: $organisationObject->getRegister(), schema: $organisationObject->getSchema(), @@ -988,10 +987,9 @@ private function ensureOrganisationEntity(object $organisationObject, array &$st $organizationSchema = ($voorzieningenConfig['organisatie_schema'] ?? ''); // Try to find existing organisation entity. - $organisationMapper = $this->container->get('OCA\OpenRegister\Db\OrganisationMapper'); try { - $organisationEntity = $organisationMapper->findByUuid($organisationId); + $organisationEntity = $this->organisationMapper->findByUuid($organisationId); // Entity exists - update it if needed. $status = strtolower(($objectData['status'] ?? 'actief')); @@ -1021,7 +1019,7 @@ private function ensureOrganisationEntity(object $organisationObject, array &$st $wasActive = $organisationEntity->getActive(); $organisationEntity->setActive($shouldBeActive); - $organisationMapper->save($organisationEntity); + $this->organisationMapper->save($organisationEntity); $stats['entitiesUpdated']++; // Send activation email if organization became active. @@ -1064,7 +1062,7 @@ private function ensureOrganisationEntity(object $organisationObject, array &$st $slug = strtolower(preg_replace('/[^a-z0-9]+/', '-', strtolower($orgName))); $slug = trim($slug, '-'); try { - $organisationEntity = $organisationMapper->findBySlug($slug); + $organisationEntity = $this->organisationMapper->findBySlug($slug); $this->logger->info( 'OrganizationSyncService: Found existing entity by slug, updating UUID to match object', [ @@ -1077,7 +1075,7 @@ private function ensureOrganisationEntity(object $organisationObject, array &$st // Update the entity's UUID to match the object UUID so future lookups work. $organisationEntity->setUuid($organisationId); - $organisationMapper->save($organisationEntity); + $this->organisationMapper->save($organisationEntity); $stats['entitiesUpdated']++; // Update organisatie object owner to this entity. @@ -1241,8 +1239,6 @@ private function getContactPersonsForOrganisation(string $organisationId, string } try { - $objectService = $this->container->get('OCA\OpenRegister\Service\ObjectService'); - // Use searchObjects for more efficient filtering on-demand. $query = [ '@self' => [ @@ -1253,7 +1249,7 @@ private function getContactPersonsForOrganisation(string $organisationId, string '_limit' => 500, ]; - $contactPersons = $objectService->searchObjects(query: $query, _rbac: false, _multitenancy: false); + $contactPersons = $this->objectService->searchObjects(query: $query, _rbac: false, _multitenancy: false); $this->logger->debug( 'OrganizationSyncService: Retrieved contact persons on-demand', @@ -1412,8 +1408,7 @@ private function updateOrganisationEntityUsers(object $organisationEntity, array $organisationEntity->setUsers($allUsernames); - $organisationMapper = $this->container->get('OCA\OpenRegister\Db\OrganisationMapper'); - $organisationMapper->save($organisationEntity); + $this->organisationMapper->save($organisationEntity); $stats['entitiesUpdated']++; @@ -1516,10 +1511,9 @@ public function getSyncStatus(int $minutesBack = 10): array { ); // Get organization entities count. - $organisationMapper = $this->container->get('OCA\OpenRegister\Db\OrganisationMapper'); $entitiesCount = 0; try { - $entities = $organisationMapper->findAllWithUserCount(); + $entities = $this->organisationMapper->findAllWithUserCount(); $entitiesCount = count($entities); } catch (\Exception $e) { // Ignore errors in count. @@ -1857,8 +1851,7 @@ private function processNestedContactPersons($organizationObject, array &$stats) ); // Fetch the contact person object using the UUID. - $objectService = $this->container->get('OCA\OpenRegister\Service\ObjectService'); - $contactObject = $objectService->find( + $contactObject = $this->objectService->find( id: $contactData, register: $register, schema: $contactSchema, @@ -1976,7 +1969,6 @@ private function processRelatedContactPersons(string $organizationUuid, $organiz } // Find all contactpersoon objects that have this organization in their organisation property. - $objectService = $this->container->get('OCA\OpenRegister\Service\ObjectService'); // Search for contactpersoon objects with this organization reference. // Try both 'organization' and 'organisation' field names. @@ -1999,7 +1991,7 @@ private function processRelatedContactPersons(string $organizationUuid, $organiz ] ); - $relatedContacts = $objectService->searchObjects($query); + $relatedContacts = $this->objectService->searchObjects($query); // If not found, try with 'organisation' field. if (empty($relatedContacts) === true) { @@ -2014,7 +2006,7 @@ private function processRelatedContactPersons(string $organizationUuid, $organiz ] ); - $relatedContacts = $objectService->searchObjects($query); + $relatedContacts = $this->objectService->searchObjects($query); } if (empty($relatedContacts) === true) { @@ -2032,7 +2024,7 @@ private function processRelatedContactPersons(string $organizationUuid, $organiz $orgRegister = ($voorzieningenConfig2['register'] ?? ''); $orgSchema = ($voorzieningenConfig2['organisatie_schema'] ?? ''); - $rawOrgObject = $objectService->find( + $rawOrgObject = $this->objectService->find( id: $organizationUuid, register: $orgRegister, schema: $orgSchema, @@ -2063,7 +2055,7 @@ private function processRelatedContactPersons(string $organizationUuid, $organiz } try { - $contactObj = $objectService->find( + $contactObj = $this->objectService->find( id: $contactUuid, register: $register, schema: $contactSchema, @@ -2131,7 +2123,7 @@ private function processRelatedContactPersons(string $organizationUuid, $organiz ); try { - $fullContactObject = $objectService->find( + $fullContactObject = $this->objectService->find( id: $contactUuid, register: $register, schema: $contactSchema, @@ -2160,8 +2152,16 @@ private function processRelatedContactPersons(string $organizationUuid, $organiz if (empty($contactData['organization']) === true) { $contactData['organization'] = $organizationUuid; $contactObject->setObject($contactData); - $objectMapper = $this->container->get('OCA\OpenRegister\Db\MagicMapper'); - $objectMapper->update($contactObject); + // Published contract instead of OpenRegister's Db layer; see + // ContactpersonenController for the reasoning. + $this->objectService->saveObject( + object: $contactData, + register: $contactObject->getRegister(), + schema: $contactObject->getSchema(), + uuid: $contactObject->getUuid(), + silent: true, + _validation: false + ); $this->logger->info( '[FLOW] Set missing organisatie field on related contact', [ @@ -2241,8 +2241,6 @@ private function createOrUpdateContactPersonObject( array &$stats, ): void { try { - $objectService = $this->container->get('OCA\OpenRegister\Service\ObjectService'); - $email = ($contactData['email'] ?? $contactData['e-mailadres'] ?? ''); if (empty($email) === true) { $this->logger->warning( @@ -2272,7 +2270,7 @@ private function createOrUpdateContactPersonObject( ); try { - $contactObject = $objectService->find( + $contactObject = $this->objectService->find( id: $existingContactId, register: $register, schema: $contactSchema, @@ -2310,7 +2308,7 @@ private function createOrUpdateContactPersonObject( unset($contactData['id']); unset($contactData['uuid']); - $contactObject = $objectService->saveObject( + $contactObject = $this->objectService->saveObject( object: $contactData, register: $register, schema: $contactSchema, @@ -2323,8 +2321,18 @@ private function createOrUpdateContactPersonObject( $restoredData = $contactObject->getObject(); $restoredData['organization'] = $savedOrganisation; $contactObject->setObject($restoredData); - $objectMapper = $this->container->get('OCA\OpenRegister\Db\MagicMapper'); - $objectMapper->update($contactObject); + // Published contract instead of OpenRegister's Db layer. + $this->objectService->saveObject( + object: array_merge( + $contactObject->getObject(), + ['@self' => ['organisation' => $contactObject->getOrganisation()]] + ), + register: $contactObject->getRegister(), + schema: $contactObject->getSchema(), + uuid: $contactObject->getUuid(), + silent: true, + _validation: false + ); } }//end if @@ -2337,8 +2345,18 @@ private function createOrUpdateContactPersonObject( $contactObjectData['organization'] = $organizationUuid; $contactObject->setObject($contactObjectData); $contactObject->setOrganisation($organizationUuid); - $objectMapper = $this->container->get('OCA\OpenRegister\Db\MagicMapper'); - $objectMapper->update($contactObject); + // Published contract instead of OpenRegister's Db layer. + $this->objectService->saveObject( + object: array_merge( + $contactObject->getObject(), + ['@self' => ['organisation' => $contactObject->getOrganisation()]] + ), + register: $contactObject->getRegister(), + schema: $contactObject->getSchema(), + uuid: $contactObject->getUuid(), + silent: true, + _validation: false + ); $this->logger->info( '[FLOW] Set missing organisatie field on contact person', [ @@ -2364,8 +2382,7 @@ private function createOrUpdateContactPersonObject( // Check if organization exists in organisation entity table. $organisationEntity = null; try { - $organisationMapper = $this->container->get('OCA\OpenRegister\Db\OrganisationMapper'); - $organisationEntity = $organisationMapper->findByUuid($organizationUuid); + $organisationEntity = $this->organisationMapper->findByUuid($organizationUuid); } catch (\OCP\AppFramework\Db\DoesNotExistException $e) { // Backup: org entity missing — create it now so user creation can proceed. $this->logger->info( @@ -2377,7 +2394,7 @@ private function createOrUpdateContactPersonObject( ); try { $voorzieningenConfig = $this->settingsService->getVoorzieningenConfig(); - $orgObject = $objectService->find( + $orgObject = $this->objectService->find( id: $organizationUuid, register: ($voorzieningenConfig['register'] ?? ''), schema: ($voorzieningenConfig['organisatie_schema'] ?? '') @@ -2456,8 +2473,18 @@ private function createOrUpdateContactPersonObject( ); try { - $objectMapper = $this->container->get('OCA\OpenRegister\Db\MagicMapper'); - $objectMapper->update($contactObject); + // Published contract instead of OpenRegister's Db layer. + $this->objectService->saveObject( + object: array_merge( + $contactObject->getObject(), + ['@self' => ['organisation' => $contactObject->getOrganisation()]] + ), + register: $contactObject->getRegister(), + schema: $contactObject->getSchema(), + uuid: $contactObject->getUuid(), + silent: true, + _validation: false + ); $this->logger->info( 'Contact saved with username', [ @@ -2620,8 +2647,7 @@ public function processSpecificContactPerson($contactObject): array { // Check if organization exists in organisation entity table. $organisationEntity = null; try { - $organisationMapper = $this->container->get('OCA\OpenRegister\Db\OrganisationMapper'); - $organisationEntity = $organisationMapper->findByUuid($organizationUuid); + $organisationEntity = $this->organisationMapper->findByUuid($organizationUuid); } catch (\OCP\AppFramework\Db\DoesNotExistException $e) { // Backup: org entity missing — create it now so user creation can proceed. $this->logger->info( @@ -2633,8 +2659,7 @@ public function processSpecificContactPerson($contactObject): array { ); try { $voorzieningenConfig = $this->settingsService->getVoorzieningenConfig(); - $objectService = $this->container->get('OCA\OpenRegister\Service\ObjectService'); - $orgObject = $objectService->find( + $orgObject = $this->objectService->find( id: $organizationUuid, register: ($voorzieningenConfig['register'] ?? ''), schema: ($voorzieningenConfig['organisatie_schema'] ?? '') @@ -2697,8 +2722,7 @@ public function processSpecificContactPerson($contactObject): array { // that may fail — but the user was already created successfully above. try { $contactObject->setObject($contactEntityObject); - $objectService = $this->container->get('OCA\OpenRegister\Service\ObjectService'); - $objectService->saveObject( + $this->objectService->saveObject( object: $contactObject, register: $register, schema: $contactSchema, @@ -3183,8 +3207,18 @@ private function updateOrganisationObjectOwner( $organisationObject->setOrganisation($organisationEntityUuid); // Save using MagicMapper directly to bypass validation and ensure metadata is persisted. - $objectMapper = $this->container->get('OCA\OpenRegister\Db\MagicMapper'); - $objectMapper->update($organisationObject); + // Published contract instead of OpenRegister's Db layer. + $this->objectService->saveObject( + object: array_merge( + $organisationObject->getObject(), + ['@self' => ['organisation' => $organisationObject->getOrganisation()]] + ), + register: $organisationObject->getRegister(), + schema: $organisationObject->getSchema(), + uuid: $organisationObject->getUuid(), + silent: true, + _validation: false + ); $this->logger->info( 'OrganizationSyncService: Successfully updated organisatie object owner and organisation', @@ -3298,8 +3332,18 @@ private function updateContactPersonObjectOwner( } // Save using MagicMapper directly to bypass validation and ensure metadata is persisted. - $objectMapper = $this->container->get('OCA\OpenRegister\Db\MagicMapper'); - $objectMapper->update($contactObject); + // Published contract instead of OpenRegister's Db layer. + $this->objectService->saveObject( + object: array_merge( + $contactObject->getObject(), + ['@self' => ['organisation' => $contactObject->getOrganisation()]] + ), + register: $contactObject->getRegister(), + schema: $contactObject->getSchema(), + uuid: $contactObject->getUuid(), + silent: true, + _validation: false + ); $this->logger->info( 'OrganizationSyncService: Successfully updated contactpersoon object owner and organisation', diff --git a/lib/Service/PortfolioReportService.php b/lib/Service/PortfolioReportService.php index ead9d5d4..2972a813 100644 --- a/lib/Service/PortfolioReportService.php +++ b/lib/Service/PortfolioReportService.php @@ -34,7 +34,7 @@ use DateTimeImmutable; use Exception; -use OCA\OpenRegister\Service\ObjectService; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCA\SoftwareCatalog\AppInfo\Application; use OCP\App\IAppManager; use OCP\IAppConfig; @@ -558,11 +558,11 @@ private function getPageSizeCeiling(): int { /** * Lazily resolve the OpenRegister ObjectService. * - * @return ObjectService The service. + * @return ObjectServiceInterface The service. * * @throws Exception When OpenRegister is not installed or unresolvable. */ - private function getObjectService(): ObjectService { + private function getObjectService(): ObjectServiceInterface { if (in_array('openregister', $this->appManager->getInstalledApps(), true) === false) { throw new Exception('OpenRegister app is not installed'); } diff --git a/lib/Service/PublicationService.php b/lib/Service/PublicationService.php index ca608dca..73829b55 100644 --- a/lib/Service/PublicationService.php +++ b/lib/Service/PublicationService.php @@ -34,7 +34,7 @@ namespace OCA\SoftwareCatalog\Service; -use OCA\OpenRegister\Service\ObjectService; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; @@ -288,9 +288,9 @@ private function now(): string { /** * Get the OpenRegister ObjectService from the DI container. * - * @return ObjectService|null The object service, or null when OR is absent. + * @return ObjectServiceInterface|null The object service, or null when OR is absent. */ - private function getObjectService(): ?ObjectService { + private function getObjectService(): ?ObjectServiceInterface { try { return $this->container->get('OCA\OpenRegister\Service\ObjectService'); } catch (\Throwable $e) { diff --git a/lib/Service/SbomImportService.php b/lib/Service/SbomImportService.php index fcf56995..c6638076 100644 --- a/lib/Service/SbomImportService.php +++ b/lib/Service/SbomImportService.php @@ -39,7 +39,7 @@ namespace OCA\SoftwareCatalog\Service; use DateTime; -use OCA\OpenRegister\Service\ObjectService; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; use RuntimeException; @@ -330,7 +330,7 @@ public function getStatus(string $moduleVersieUuid, ?string $operationId = null) * in bounded batches. OR's search already excludes `_deleted` rows by * default, so a prior replace's trashed rows are never re-queried. * - * @param ObjectService $objectService The OR object service. + * @param ObjectServiceInterface $objectService The OR object service. * @param int $registerId The voorzieningen register id. * @param int $componentSchemaId The sbomComponent schema id. * @param string $moduleVersieUuid The target moduleVersie uuid. @@ -340,7 +340,7 @@ public function getStatus(string $moduleVersieUuid, ?string $operationId = null) * @spec openspec/specs/sbom-import/spec.md#requirement-re-import-replaces-the-previous-component-set-and-is-soft-delete-aware */ private function replacePreviousComponentSet( - ObjectService $objectService, + ObjectServiceInterface $objectService, int $registerId, int $componentSchemaId, string $moduleVersieUuid, @@ -378,7 +378,7 @@ private function replacePreviousComponentSet( * Bulk-save the newly parsed component set in bounded batches, reporting * progress per batch when tracking is active. * - * @param ObjectService $objectService The OR object service. + * @param ObjectServiceInterface $objectService The OR object service. * @param int $registerId The voorzieningen register id. * @param int $componentSchemaId The sbomComponent schema id. * @param string $moduleVersieUuid The target moduleVersie uuid. @@ -391,7 +391,7 @@ private function replacePreviousComponentSet( * @spec openspec/specs/sbom-import/spec.md#requirement-large-imports-run-in-bounded-batches-with-progress-reporting */ private function createComponentSet( - ObjectService $objectService, + ObjectServiceInterface $objectService, int $registerId, int $componentSchemaId, string $moduleVersieUuid, @@ -437,7 +437,7 @@ private function createComponentSet( * provenance fields are changed (an omitted field would otherwise be * nulled by `saveObject()`). * - * @param ObjectService $objectService The OR object service. + * @param ObjectServiceInterface $objectService The OR object service. * @param int $registerId The voorzieningen register id. * @param int $versionSchemaId The moduleVersie schema id. * @param object $moduleVersion The current moduleVersie entity. @@ -449,7 +449,7 @@ private function createComponentSet( * @spec openspec/specs/sbom-import/spec.md#requirement-moduleversie-records-sbom-import-provenance */ private function recordProvenance( - ObjectService $objectService, + ObjectServiceInterface $objectService, int $registerId, int $versionSchemaId, object $moduleVersion, @@ -609,9 +609,9 @@ private function resolveCoordinates(): array { /** * Get the OpenRegister ObjectService from the DI container. * - * @return ObjectService|null The object service, or null if not available. + * @return ObjectServiceInterface|null The object service, or null if not available. */ - private function getObjectService(): ?ObjectService { + private function getObjectService(): ?ObjectServiceInterface { try { return $this->container->get('OCA\OpenRegister\Service\ObjectService'); } catch (\Exception $e) { diff --git a/lib/Service/SettingsService.php b/lib/Service/SettingsService.php index 934857ba..b08f7d58 100644 --- a/lib/Service/SettingsService.php +++ b/lib/Service/SettingsService.php @@ -190,12 +190,12 @@ public function isOpenRegisterEnabled(): bool { /** * Attempts to retrieve the OpenRegister service from the container * - * @return \OCA\OpenRegister\Service\ObjectService|null The OpenRegister service if available + * @return \OCA\OpenRegister\Contract\ObjectServiceInterface|null The OpenRegister service if available * * @throws \RuntimeException If the service is not available * @spec openspec/specs/settings-service/spec.md */ - public function getObjectService(): ?\OCA\OpenRegister\Service\ObjectService { + public function getObjectService(): ?\OCA\OpenRegister\Contract\ObjectServiceInterface { if (in_array(needle: 'openregister', haystack: $this->appManager->getInstalledApps()) === true) { return $this->container->get('OCA\OpenRegister\Service\ObjectService'); } diff --git a/lib/Service/SoftwareCatalogue/ApiClient.php b/lib/Service/SoftwareCatalogue/ApiClient.php index a0e193b6..baad662f 100644 --- a/lib/Service/SoftwareCatalogue/ApiClient.php +++ b/lib/Service/SoftwareCatalogue/ApiClient.php @@ -23,7 +23,7 @@ namespace OCA\SoftwareCatalog\Service\SoftwareCatalogue; -use OCA\OpenRegister\Service\ObjectService; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use Psr\Log\LoggerInterface; /** @@ -39,13 +39,13 @@ class ApiClient { /** * Constructor. * - * @param ObjectService $objectService The OpenRegister object service. + * @param ObjectServiceInterface $objectService The OpenRegister object service. * @param LoggerInterface $logger Logger instance. * * @spec openspec/changes/method-decomposition/tasks.md#task-2 */ public function __construct( - private readonly ObjectService $objectService, + private readonly ObjectServiceInterface $objectService, private readonly LoggerInterface $logger, ) { }//end __construct() diff --git a/lib/Service/SoftwareCatalogue/ContactPersonHandler.php b/lib/Service/SoftwareCatalogue/ContactPersonHandler.php index dd2e148f..8c7a0297 100644 --- a/lib/Service/SoftwareCatalogue/ContactPersonHandler.php +++ b/lib/Service/SoftwareCatalogue/ContactPersonHandler.php @@ -87,10 +87,10 @@ public function __construct( /** * Gets the OpenRegister ObjectService if available * - * @return \OCA\OpenRegister\Service\ObjectService|null ObjectService instance or null + * @return \OCA\OpenRegister\Contract\ObjectServiceInterface|null ObjectService instance or null * @throws \RuntimeException If service is not available */ - private function getObjectService(): ?\OCA\OpenRegister\Service\ObjectService { + private function getObjectService(): ?\OCA\OpenRegister\Contract\ObjectServiceInterface { if (in_array('openregister', $this->_appManager->getInstalledApps()) === true) { return $this->_container->get('OCA\OpenRegister\Service\ObjectService'); } diff --git a/lib/Service/SoftwareCatalogue/GroupHandler.php b/lib/Service/SoftwareCatalogue/GroupHandler.php index fbf5ee8d..aa48e2f3 100644 --- a/lib/Service/SoftwareCatalogue/GroupHandler.php +++ b/lib/Service/SoftwareCatalogue/GroupHandler.php @@ -21,7 +21,7 @@ namespace OCA\SoftwareCatalog\Service\SoftwareCatalogue; -use OCA\OpenRegister\Service\ObjectService; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCP\App\IAppManager; use OCP\IAppConfig; use OCP\IGroup; @@ -82,11 +82,11 @@ public function __construct( /** * Gets the OpenRegister ObjectService if available * - * @return ObjectService|null ObjectService instance or null + * @return ObjectServiceInterface|null ObjectService instance or null * * @throws RuntimeException If service is not available */ - private function getObjectService(): ?ObjectService { + private function getObjectService(): ?ObjectServiceInterface { if (in_array(needle: 'openregister', haystack: $this->_appManager->getInstalledApps()) === true) { return $this->_container->get('OCA\OpenRegister\Service\ObjectService'); } diff --git a/lib/Service/SoftwareCatalogue/OrganizationHandler.php b/lib/Service/SoftwareCatalogue/OrganizationHandler.php index 15bfbbe1..fff7438f 100644 --- a/lib/Service/SoftwareCatalogue/OrganizationHandler.php +++ b/lib/Service/SoftwareCatalogue/OrganizationHandler.php @@ -75,11 +75,11 @@ public function __construct( /** * Gets the OpenRegister ObjectService if available. * - * @return \OCA\OpenRegister\Service\ObjectService|null ObjectService instance or null + * @return \OCA\OpenRegister\Contract\ObjectServiceInterface|null ObjectService instance or null * * @throws \RuntimeException If service is not available */ - private function getObjectService(): ?\OCA\OpenRegister\Service\ObjectService { + private function getObjectService(): ?\OCA\OpenRegister\Contract\ObjectServiceInterface { if (in_array(needle: 'openregister', haystack: $this->_appManager->getInstalledApps()) === true) { return $this->_container->get('OCA\OpenRegister\Service\ObjectService'); } @@ -477,7 +477,7 @@ public function processContactpersonen(object $organizationObject): array { * * @param string $email The email address to search for * @param string $organizationUuid The organization UUID - * @param \OCA\OpenRegister\Service\ObjectService $objectService The object service + * @param \OCA\OpenRegister\Contract\ObjectServiceInterface $objectService The object service * @param int $registerId The register ID * @param int $contactgegevensSchemaId The contactgegevens schema ID * @@ -486,7 +486,7 @@ public function processContactpersonen(object $organizationObject): array { private function findExistingContactgegevens( string $email, string $organizationUuid, - \OCA\OpenRegister\Service\ObjectService $objectService, + \OCA\OpenRegister\Contract\ObjectServiceInterface $objectService, int $registerId, int $contactgegevensSchemaId, ): ?object { diff --git a/lib/Service/SoftwareCatalogueService.php b/lib/Service/SoftwareCatalogueService.php index b5cf7834..e4249246 100644 --- a/lib/Service/SoftwareCatalogueService.php +++ b/lib/Service/SoftwareCatalogueService.php @@ -107,9 +107,9 @@ public function __construct( /** * Gets the ObjectService instance * - * @return \OCA\OpenRegister\Service\ObjectService|null + * @return \OCA\OpenRegister\Contract\ObjectServiceInterface|null */ - private function getObjectService(): ?\OCA\OpenRegister\Service\ObjectService { + private function getObjectService(): ?\OCA\OpenRegister\Contract\ObjectServiceInterface { if ($this->_appManager->isEnabledForUser(appId: 'openregister') === false) { return null; } @@ -2028,10 +2028,19 @@ private function activateUsersForOrganization(string $organizationUuid): void { $registerId = $ctx['registerId']; $contactPersonSchemaId = $ctx['schemaId']; + // findAll() takes ($config, bool $_rbac, bool $_multitenancy). The + // register and schema belong inside the config's filters, as the + // sibling call above does -- passed positionally they landed on the + // two booleans, so this ran unscoped across every register with + // $_rbac set to a register id. $contactpersonen = $objectService->findAll( - ['organisation' => $organizationUuid], - $registerId, - $contactPersonSchemaId + [ + 'filters' => [ + 'register' => $registerId, + 'schema' => $contactPersonSchemaId, + 'organisation' => $organizationUuid, + ], + ] ); $userManager = $this->_container->get(\OCP\IUserManager::class); @@ -2111,10 +2120,19 @@ private function deactivateUsersForOrganization(string $organizationUuid): void $registerId = $ctx['registerId']; $contactPersonSchemaId = $ctx['schemaId']; + // findAll() takes ($config, bool $_rbac, bool $_multitenancy). The + // register and schema belong inside the config's filters, as the + // sibling call above does -- passed positionally they landed on the + // two booleans, so this ran unscoped across every register with + // $_rbac set to a register id. $contactpersonen = $objectService->findAll( - ['organisation' => $organizationUuid], - $registerId, - $contactPersonSchemaId + [ + 'filters' => [ + 'register' => $registerId, + 'schema' => $contactPersonSchemaId, + 'organisation' => $organizationUuid, + ], + ] ); $userManager = $this->_container->get(\OCP\IUserManager::class); diff --git a/lib/Service/ViewService.php b/lib/Service/ViewService.php index b37d2629..2ce681b3 100644 --- a/lib/Service/ViewService.php +++ b/lib/Service/ViewService.php @@ -21,6 +21,7 @@ namespace OCA\SoftwareCatalog\Service; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCA\OpenRegister\Service\ObjectService; use OCP\App\IAppManager; use OCP\IAppConfig; @@ -1398,9 +1399,9 @@ private function getNodeDeelnamesGebruik(string $modelNodeId, array $deelnamesGe /** * Get ObjectService from container. * - * @return ObjectService|null ObjectService instance or null if not available. + * @return ObjectServiceInterface|null ObjectService instance or null if not available. */ - private function getObjectService(): ?ObjectService { + private function getObjectService(): ?ObjectServiceInterface { if ($this->appManager->isInstalled('openregister') === false) { return null; } diff --git a/tests/OrganizationSyncTest.php b/tests/OrganizationSyncTest.php index 3ae773cd..0105631c 100644 --- a/tests/OrganizationSyncTest.php +++ b/tests/OrganizationSyncTest.php @@ -17,7 +17,7 @@ namespace OCA\SoftwareCatalog\Tests; -use OCA\OpenRegister\Service\ObjectService; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCA\SoftwareCatalog\Service\SettingsService; use OCA\SoftwareCatalog\Service\SoftwareCatalogueService; use OCP\AppFramework\Db\Entity; @@ -43,7 +43,7 @@ class OrganizationSyncTest extends TestCase { */ public function testOrganizationCreationSync(): void { // Mock dependencies - $objectService = $this->createMock(ObjectService::class); + $objectService = $this->createMock(ObjectServiceInterface::class); $settingsService = $this->createMock(SettingsService::class); $userManager = $this->createMock(IUserManager::class); $groupManager = $this->createMock(IGroupManager::class); @@ -93,7 +93,10 @@ public function testOrganizationCreationSync(): void { $this->createMock(\OCA\SoftwareCatalog\Service\SymfonyEmailService::class), $this->createMock(\Psr\Log\LoggerInterface::class), $this->createMock(\Psr\Container\ContainerInterface::class), - $this->createMock(\OCP\App\IAppManager::class) + $this->createMock(\OCP\App\IAppManager::class), + _userSession: $this->createMock(IUserSession::class), + _userManager: $this->createMock(IUserManager::class), + _groupManager: $this->createMock(IGroupManager::class), ); // Test synchronization @@ -143,7 +146,7 @@ public function testOrganizationStatusMapping(): void { */ public function testContactpersoonOrganizationMembership(): void { // Mock dependencies - $objectService = $this->createMock(ObjectService::class); + $objectService = $this->createMock(ObjectServiceInterface::class); $settingsService = $this->createMock(SettingsService::class); // Configure mocks diff --git a/tests/Stubs/Db/ObjectEntity.php b/tests/Stubs/Db/ObjectEntity.php index 890451af..34311c7b 100644 --- a/tests/Stubs/Db/ObjectEntity.php +++ b/tests/Stubs/Db/ObjectEntity.php @@ -57,7 +57,21 @@ /** * Stub for ObjectEntity with the surface used by SoftwareCatalog tests. */ -abstract class ObjectEntity { +abstract class ObjectEntity implements \OCA\OpenRegister\Contract\ObjectEntityInterface { + /** + * @return ?string + */ + public function getOrganisation(): ?string { + return $this->organisation ?? null; + } + + /** + * @return ?string + */ + public function getOwner(): ?string { + return $this->owner ?? null; + } + /** * The system-level owning organisation (`@self.organisation`). diff --git a/tests/Unit/Controller/ContactpersonenControllerOrganisationScopeTest.php b/tests/Unit/Controller/ContactpersonenControllerOrganisationScopeTest.php index 0579b189..8e1c423f 100644 --- a/tests/Unit/Controller/ContactpersonenControllerOrganisationScopeTest.php +++ b/tests/Unit/Controller/ContactpersonenControllerOrganisationScopeTest.php @@ -27,7 +27,9 @@ namespace OCA\SoftwareCatalog\Tests\Unit\Controller; use OCA\OpenRegister\Db\ObjectEntity; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCA\OpenRegister\Service\ObjectService; +use OCA\OpenRegister\Service\OrganisationService; use OCA\SoftwareCatalog\Controller\ContactpersonenController; use OCA\SoftwareCatalog\Service\ContactpersoonService; use OCA\SoftwareCatalog\Service\SettingsService; @@ -74,8 +76,8 @@ class ContactpersonenControllerOrganisationScopeTest extends TestCase { /** @var ContainerInterface|MockObject */ private ContainerInterface|MockObject $container; - /** @var ObjectService|MockObject */ - private ObjectService|MockObject $objectService; + /** @var ObjectServiceInterface|MockObject */ + private ObjectServiceInterface|MockObject $objectService; /** @var ContactpersoonService|MockObject */ private ContactpersoonService|MockObject $contactSvc; @@ -96,7 +98,7 @@ protected function setUp(): void { $this->userManager = $this->createMock(IUserManager::class); $this->groupManager = $this->createMock(IGroupManager::class); $this->userSession = $this->createMock(IUserSession::class); - $this->objectService = $this->createMock(ObjectService::class); + $this->objectService = $this->createMock(ObjectServiceInterface::class); $this->contactSvc = $this->createMock(ContactpersoonService::class); $this->logger = $this->createMock(LoggerInterface::class); $this->container = $this->createMock(ContainerInterface::class); @@ -117,7 +119,9 @@ protected function setUp(): void { $this->userSession, $this->container, $this->createMock(ISecureRandom::class), - $this->logger + $this->logger, + objectService: $this->createMock(ObjectServiceInterface::class), + organisationService: $this->createMock(OrganisationService::class), ); }//end setUp() diff --git a/tests/Unit/Controller/ContactpersonenControllerUpdateUserGroupsTest.php b/tests/Unit/Controller/ContactpersonenControllerUpdateUserGroupsTest.php index 6040f3af..28068f0e 100644 --- a/tests/Unit/Controller/ContactpersonenControllerUpdateUserGroupsTest.php +++ b/tests/Unit/Controller/ContactpersonenControllerUpdateUserGroupsTest.php @@ -20,7 +20,9 @@ namespace OCA\SoftwareCatalog\Tests\Unit\Controller; use OCA\OpenRegister\Db\ObjectEntity; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCA\OpenRegister\Service\ObjectService; +use OCA\OpenRegister\Service\OrganisationService; use OCA\SoftwareCatalog\Controller\ContactpersonenController; use OCA\SoftwareCatalog\Service\ContactpersoonService; use OCA\SoftwareCatalog\Service\SettingsService; @@ -61,8 +63,8 @@ class ContactpersonenControllerUpdateUserGroupsTest extends TestCase { /** @var ContainerInterface|MockObject */ private ContainerInterface|MockObject $container; - /** @var ObjectService|MockObject */ - private ObjectService|MockObject $objectService; + /** @var ObjectServiceInterface|MockObject */ + private ObjectServiceInterface|MockObject $objectService; /** @var LoggerInterface|MockObject */ private LoggerInterface|MockObject $logger; @@ -80,7 +82,7 @@ protected function setUp(): void { $this->userManager = $this->createMock(IUserManager::class); $this->groupManager = $this->createMock(IGroupManager::class); $this->userSession = $this->createMock(IUserSession::class); - $this->objectService = $this->createMock(ObjectService::class); + $this->objectService = $this->createMock(ObjectServiceInterface::class); $this->logger = $this->createMock(LoggerInterface::class); $this->container = $this->createMock(ContainerInterface::class); @@ -100,7 +102,9 @@ protected function setUp(): void { $this->userSession, $this->container, $this->createMock(ISecureRandom::class), - $this->logger + $this->logger, + objectService: $this->createMock(ObjectServiceInterface::class), + organisationService: $this->createMock(OrganisationService::class), ); }//end setUp() diff --git a/tests/Unit/Controller/ContactpersonenControllerUserAdminContractTest.php b/tests/Unit/Controller/ContactpersonenControllerUserAdminContractTest.php index 1bc4d5c8..6ebc59cf 100644 --- a/tests/Unit/Controller/ContactpersonenControllerUserAdminContractTest.php +++ b/tests/Unit/Controller/ContactpersonenControllerUserAdminContractTest.php @@ -30,6 +30,8 @@ namespace OCA\SoftwareCatalog\Tests\Unit\Controller; +use OCA\OpenRegister\Contract\ObjectServiceInterface; +use OCA\OpenRegister\Service\OrganisationService; use OCA\SoftwareCatalog\Controller\ContactpersonenController; use OCA\SoftwareCatalog\Service\ContactpersoonService; use OCA\SoftwareCatalog\Service\SettingsService; @@ -114,7 +116,9 @@ private function makeController(): ContactpersonenController { $this->userSession, $this->container, $this->createMock(ISecureRandom::class), - $this->createMock(LoggerInterface::class) + $this->createMock(LoggerInterface::class), + objectService: $this->createMock(ObjectServiceInterface::class), + organisationService: $this->createMock(OrganisationService::class), ); }//end makeController() diff --git a/tests/Unit/EventListener/UserProfileUpdatedEventListenerDecompositionTest.php b/tests/Unit/EventListener/UserProfileUpdatedEventListenerDecompositionTest.php index f8809d7a..0c00e089 100644 --- a/tests/Unit/EventListener/UserProfileUpdatedEventListenerDecompositionTest.php +++ b/tests/Unit/EventListener/UserProfileUpdatedEventListenerDecompositionTest.php @@ -21,6 +21,8 @@ namespace OCA\SoftwareCatalog\Tests\Unit\EventListener; +use OCA\OpenRegister\Contract\ObjectServiceInterface; +use OCA\OpenRegister\Db\SchemaMapper; use OCA\OpenRegister\Event\UserProfileUpdatedEvent; use OCA\SoftwareCatalog\EventListener\UserProfileUpdatedEventListener; use PHPUnit\Framework\TestCase; @@ -49,7 +51,12 @@ private function makeListener(): UserProfileUpdatedEventListener { $this->markTestSkipped('OCA\\OpenRegister\\Event\\UserProfileUpdatedEvent is not autoloadable in this environment.'); } - return new UserProfileUpdatedEventListener($this->createMock(ContainerInterface::class)); + return new UserProfileUpdatedEventListener($this->createMock(ContainerInterface::class), + objectService: $this->createMock(ObjectServiceInterface::class), + schemaMapper: $this->createMock(SchemaMapper::class), + registerMapper: $this->createMock(RegisterMapper::class), + metadataHydrationHandler: $this->createMock(MetadataHydrationHandler::class), + ); }//end makeListener() /** diff --git a/tests/Unit/OrganisationUserWorkflowTest.php b/tests/Unit/OrganisationUserWorkflowTest.php index d36d02cc..f3c17728 100644 --- a/tests/Unit/OrganisationUserWorkflowTest.php +++ b/tests/Unit/OrganisationUserWorkflowTest.php @@ -22,7 +22,9 @@ namespace OCA\SoftwareCatalog\Tests\Unit; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCA\OpenRegister\Service\ObjectService; +use OCA\OpenRegister\Service\OrganisationService; use OCA\SoftwareCatalog\Controller\ContactpersonenController; use OCA\SoftwareCatalog\Service\ContactpersoonService; use OCA\SoftwareCatalog\Service\SettingsService; @@ -53,9 +55,9 @@ class OrganisationUserWorkflowTest extends TestCase { /** * Mock of the ObjectService * - * @var ObjectService|MockObject + * @var ObjectServiceInterface|MockObject */ - private ObjectService|MockObject $objectService; + private ObjectServiceInterface|MockObject $objectService; /** * Mock of the IUserManager service @@ -139,7 +141,7 @@ protected function setUp(): void { ); // Create mocks - $this->objectService = $this->createMock(ObjectService::class); + $this->objectService = $this->createMock(ObjectServiceInterface::class); $this->userManager = $this->createMock(IUserManager::class); $this->groupManager = $this->createMock(IGroupManager::class); $this->contactPersonHandler = $this->createMock(ContactPersonHandler::class); @@ -159,7 +161,9 @@ protected function setUp(): void { $this->createMock(IUserSession::class), $this->createMock(ContainerInterface::class), $this->createMock(ISecureRandom::class), - $this->logger + $this->logger, + objectService: $this->createMock(ObjectServiceInterface::class), + organisationService: $this->createMock(OrganisationService::class), ); } @@ -386,7 +390,7 @@ private function createContactPerson( * @return array The result of user creation */ private function convertContactPersonToUser(array $contactPersonData): array { - // Mock the ObjectService + // Mock the ObjectServiceInterface $contactPersonObject = $this->createMockObjectEntity( uuid: $contactPersonData['uuid'], data: $contactPersonData, diff --git a/tests/Unit/SbomImportServiceTest.php b/tests/Unit/SbomImportServiceTest.php index 706e3598..dc23f2c1 100644 --- a/tests/Unit/SbomImportServiceTest.php +++ b/tests/Unit/SbomImportServiceTest.php @@ -29,6 +29,7 @@ namespace OCA\SoftwareCatalog\Tests\Unit; use OCA\OpenRegister\Db\ObjectEntity; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCA\OpenRegister\Service\ObjectService; use OCA\SoftwareCatalog\Exception\UnsupportedSbomFormatException; use OCA\SoftwareCatalog\Service\ProgressTracker; @@ -50,9 +51,9 @@ class SbomImportServiceTest extends TestCase { private string $fixturesDir; /** - * @var ObjectService|MockObject + * @var ObjectServiceInterface|MockObject */ - private ObjectService|MockObject $objectService; + private ObjectServiceInterface|MockObject $objectService; /** * @var ProgressTracker|MockObject @@ -138,7 +139,7 @@ private function previousComponentEntity(string $uuid): ObjectEntity|MockObject private function makeService(array $moduleVersionData = ['version' => '1.0.0'], array $previousUuids = []): SbomImportService { $container = $this->createMock(ContainerInterface::class); $settings = $this->createMock(SettingsService::class); - $this->objectService = $this->createMock(ObjectService::class); + $this->objectService = $this->createMock(ObjectServiceInterface::class); $this->progressTracker = $this->createMock(ProgressTracker::class); $logger = $this->createMock(LoggerInterface::class); @@ -422,7 +423,7 @@ public function testUnsupportedFormatWritesNothing(): void { public function testModuleVersieNotFoundThrows(): void { $container = $this->createMock(ContainerInterface::class); $settings = $this->createMock(SettingsService::class); - $objectService = $this->createMock(ObjectService::class); + $objectService = $this->createMock(ObjectServiceInterface::class); $progressTracker = $this->createMock(ProgressTracker::class); $logger = $this->createMock(LoggerInterface::class); diff --git a/tests/Unit/Service/AangebodenGebruikServiceTest.php b/tests/Unit/Service/AangebodenGebruikServiceTest.php index eb8df3de..63205ff0 100644 --- a/tests/Unit/Service/AangebodenGebruikServiceTest.php +++ b/tests/Unit/Service/AangebodenGebruikServiceTest.php @@ -38,6 +38,7 @@ use OCA\OpenRegister\Db\ObjectEntity; use OCA\OpenRegister\Db\Organisation; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCA\OpenRegister\Service\ObjectService; use OCA\OpenRegister\Service\OrganisationService; use OCA\SoftwareCatalog\Service\AangebodenGebruikService; @@ -62,8 +63,8 @@ class AangebodenGebruikServiceTest extends TestCase { /** @var ContainerInterface|MockObject */ private ContainerInterface|MockObject $container; - /** @var ObjectService|MockObject */ - private ObjectService|MockObject $objectService; + /** @var ObjectServiceInterface|MockObject */ + private ObjectServiceInterface|MockObject $objectService; /** @var OrganisationService|MockObject */ private OrganisationService|MockObject $organisationService; @@ -88,7 +89,7 @@ class AangebodenGebruikServiceTest extends TestCase { private function setUpService(?string $activeOrgUuid): void { $this->appManager = $this->createMock(IAppManager::class); $this->container = $this->createMock(ContainerInterface::class); - $this->objectService = $this->createMock(ObjectService::class); + $this->objectService = $this->createMock(ObjectServiceInterface::class); $this->organisationService = $this->createMock(OrganisationService::class); $this->settingsService = $this->createMock(SettingsService::class); $this->userSession = $this->createMock(IUserSession::class); diff --git a/tests/Unit/Service/ContractApprovalServiceTest.php b/tests/Unit/Service/ContractApprovalServiceTest.php index 9089355e..1739ba70 100644 --- a/tests/Unit/Service/ContractApprovalServiceTest.php +++ b/tests/Unit/Service/ContractApprovalServiceTest.php @@ -26,7 +26,7 @@ namespace OCA\SoftwareCatalog\Tests\Unit\Service; use OCA\OpenRegister\Db\ObjectEntity; -use OCA\OpenRegister\Service\ObjectService; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCA\SoftwareCatalog\Service\ContractApprovalService; use OCA\SoftwareCatalog\Service\SettingsService; use OCP\EventDispatcher\IEventDispatcher; @@ -194,7 +194,7 @@ public function testAuthorizeSubmitOwningAanbodBeheerderIsAuthorized(): void { $this->settingsService->method('getSchemaIdForObjectType')->willReturn(3); $this->settingsService->method('getRegisterIdForObjectType')->willReturn(1); - $objectService = $this->createMock(ObjectService::class); + $objectService = $this->createMock(ObjectServiceInterface::class); $entity = $this->createMock(ObjectEntity::class); $entity->method('getObject')->willReturn(['_organisation' => 'org-a']); $objectService->method('find')->willReturn($entity); @@ -215,7 +215,7 @@ public function testAuthorizeSubmitNonOwningAanbodBeheerderIsRefused(): void { $this->settingsService->method('getSchemaIdForObjectType')->willReturn(3); $this->settingsService->method('getRegisterIdForObjectType')->willReturn(1); - $objectService = $this->createMock(ObjectService::class); + $objectService = $this->createMock(ObjectServiceInterface::class); $entity = $this->createMock(ObjectEntity::class); $entity->method('getObject')->willReturn(['_organisation' => 'org-a']); $objectService->method('find')->willReturn($entity); diff --git a/tests/Unit/Service/EolSyncServiceTest.php b/tests/Unit/Service/EolSyncServiceTest.php index f5028bb3..8f4ba7b6 100644 --- a/tests/Unit/Service/EolSyncServiceTest.php +++ b/tests/Unit/Service/EolSyncServiceTest.php @@ -23,7 +23,7 @@ namespace OCA\SoftwareCatalog\Tests\Unit\Service; -use OCA\OpenRegister\Service\ObjectService; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCA\SoftwareCatalog\Service\EolMatcherService; use OCA\SoftwareCatalog\Service\EolSyncService; use OCA\SoftwareCatalog\Service\SettingsService; @@ -129,7 +129,7 @@ public function testUnresolvableRegisterDegradesGracefully(): void { $settingsService->method('getRegisterIdForObjectType')->willReturn(1); $settingsService->method('getSchemaIdForObjectType')->willReturn(2); - $objectService = $this->createMock(ObjectService::class); + $objectService = $this->createMock(ObjectServiceInterface::class); $objectService->method('setRegister')->willThrowException(new \RuntimeException('register not found')); $settingsService->method('getObjectService')->willReturn($objectService); @@ -158,7 +158,7 @@ public function testModuleSchemaNotConfiguredDegradesGracefully(): void { $settingsService = $this->createMock(SettingsService::class); $settingsService->method('getEolSyncConfig')->willReturn(self::DEFAULT_CONFIG); $settingsService->method('isOpenRegisterInstalled')->willReturn(true); - $settingsService->method('getObjectService')->willReturn($this->createMock(ObjectService::class)); + $settingsService->method('getObjectService')->willReturn($this->createMock(ObjectServiceInterface::class)); $settingsService->method('getRegisterIdForObjectType')->willReturn(null); $service = new EolSyncService( @@ -197,7 +197,7 @@ public function testSuccessfulRunMatchesStampsAndReportsStatus(): void { $moduleVersion = ['id' => 'mv-uuid-1', 'module' => 'module-uuid-1', 'version' => '16.2', 'shortDescription' => 'keep me']; $cycle = ['product' => 'postgresql', 'cycle' => '16', 'eol' => '2028-11-09']; - $objectService = $this->createMock(ObjectService::class); + $objectService = $this->createMock(ObjectServiceInterface::class); $objectService->method('searchObjects')->willReturnCallback( function (array $query) use ($module, $moduleVersion): array { if (($query['@self']['schema'] ?? null) === 20) { @@ -271,7 +271,7 @@ public function testUnmappedModuleIsNeverProcessed(): void { $unmappedModule = ['id' => 'module-uuid-2', 'eolProductSlug' => '']; - $objectService = $this->createMock(ObjectService::class); + $objectService = $this->createMock(ObjectServiceInterface::class); $objectService->method('searchObjects')->willReturnCallback( function (array $query) use ($unmappedModule): array { if (($query['@self']['schema'] ?? null) === 20) { diff --git a/tests/Unit/Service/FacetServiceTest.php b/tests/Unit/Service/FacetServiceTest.php index 3a023913..bdd67251 100644 --- a/tests/Unit/Service/FacetServiceTest.php +++ b/tests/Unit/Service/FacetServiceTest.php @@ -25,6 +25,7 @@ namespace OCA\SoftwareCatalog\Tests\Unit\Service; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCA\OpenRegister\Service\ObjectService; use OCA\SoftwareCatalog\Service\ArchiMateService; use OCA\SoftwareCatalog\Service\FacetService; @@ -91,7 +92,7 @@ class FacetServiceTest extends TestCase { /** * Build a FacetService with the given (mocked) collaborators. * - * @param ObjectService|null $objectService Mocked ObjectService, or null to omit from container. + * @param ObjectServiceInterface|null $objectService Mocked ObjectService, or null to omit from container. * @param SettingsService|null $settingsService Mocked SettingsService (defaults to a working voorzieningen config). * @param ArchiMateService|null $archiMateService Mocked ArchiMateService (defaults to empty lookups). * @param ICache|null $cache Mocked ICache (defaults to always-miss/no-op). @@ -100,7 +101,7 @@ class FacetServiceTest extends TestCase { * @return FacetService */ private function makeService( - ?ObjectService $objectService = null, + ?ObjectServiceInterface $objectService = null, ?SettingsService $settingsService = null, ?ArchiMateService $archiMateService = null, ?ICache $cache = null, @@ -179,10 +180,10 @@ function (string $id) use ($objectService, $organisationService) { * @param array $results Objects to return. * @param array $capturedRef Reference array; every captured query is appended. * - * @return ObjectService + * @return ObjectServiceInterface */ private function makePaginatedObjectService(array $results, array &$capturedRef): ObjectService { - $objectService = $this->createMock(ObjectService::class); + $objectService = $this->createMock(ObjectServiceInterface::class); $objectService->method('searchObjectsPaginated')->willReturnCallback( function (array $query) use ($results, &$capturedRef): array { $capturedRef[] = $query; @@ -207,7 +208,7 @@ function (array $query) use ($results, &$capturedRef): array { * @return void */ public function testGetFacetsThrowsForUnsupportedSchema(): void { - $service = $this->makeService(objectService: $this->createMock(ObjectService::class)); + $service = $this->makeService(objectService: $this->createMock(ObjectServiceInterface::class)); $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessageMatches('/module.*service|service.*module/'); @@ -612,8 +613,8 @@ public function testGetFacetsAppliesOrganisationScoping(): void { * @return void */ public function testCacheKeyDiffersPerUser(): void { - $serviceAlice = $this->makeService(objectService: $this->createMock(ObjectService::class), userId: 'alice'); - $serviceBob = $this->makeService(objectService: $this->createMock(ObjectService::class), userId: 'bob'); + $serviceAlice = $this->makeService(objectService: $this->createMock(ObjectServiceInterface::class), userId: 'alice'); + $serviceBob = $this->makeService(objectService: $this->createMock(ObjectServiceInterface::class), userId: 'bob'); $reflectionAlice = new \ReflectionMethod($serviceAlice, 'buildCacheKey'); $reflectionAlice->setAccessible(true); @@ -648,7 +649,7 @@ public function testGetFacetsServesFromCacheOnHit(): void { $cache = $this->createMock(ICache::class); $cache->method('get')->willReturn($cachedPayload); - $objectService = $this->createMock(ObjectService::class); + $objectService = $this->createMock(ObjectServiceInterface::class); $objectService->expects($this->never())->method('searchObjectsPaginated'); $service = $this->makeService(objectService: $objectService, cache: $cache); @@ -667,7 +668,7 @@ public function testGetFacetsServesFromCacheOnHit(): void { * @return void */ public function testGetFacetsResolvesDienstFacetsTransitivelyViaModules(): void { - $objectService = $this->createMock(ObjectService::class); + $objectService = $this->createMock(ObjectServiceInterface::class); $capturedPaginated = []; $objectService->method('searchObjectsPaginated')->willReturnCallback( @@ -719,7 +720,7 @@ function (array $query) use (&$capturedPaginated): array { * @return void */ public function testGetFacetsResolvesDienstFacetsWhenBothLookupsReturnObjectEntityInstances(): void { - $objectService = $this->createMock(ObjectService::class); + $objectService = $this->createMock(ObjectServiceInterface::class); $capturedPaginated = []; $objectService->method('searchObjectsPaginated')->willReturnCallback( diff --git a/tests/Unit/Service/GebruikServiceGetApplicationIdsTest.php b/tests/Unit/Service/GebruikServiceGetApplicationIdsTest.php index 1c3de981..1f1ff614 100644 --- a/tests/Unit/Service/GebruikServiceGetApplicationIdsTest.php +++ b/tests/Unit/Service/GebruikServiceGetApplicationIdsTest.php @@ -20,6 +20,7 @@ namespace OCA\SoftwareCatalog\Tests\Unit\Service; use OCA\OpenRegister\Db\ObjectEntity; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCA\OpenRegister\Service\ObjectService; use OCA\SoftwareCatalog\Service\GebruikService; use OCA\SoftwareCatalog\Service\SettingsService; @@ -50,8 +51,8 @@ class GebruikServiceGetApplicationIdsTest extends TestCase { /** @var ContainerInterface|MockObject */ private ContainerInterface|MockObject $container; - /** @var ObjectService|MockObject */ - private ObjectService|MockObject $objectService; + /** @var ObjectServiceInterface|MockObject */ + private ObjectServiceInterface|MockObject $objectService; /** @var LoggerInterface|MockObject */ private LoggerInterface|MockObject $logger; @@ -68,7 +69,7 @@ protected function setUp(): void { $this->settingsService = $this->createMock(SettingsService::class); $this->appManager = $this->createMock(IAppManager::class); - $this->objectService = $this->createMock(ObjectService::class); + $this->objectService = $this->createMock(ObjectServiceInterface::class); $this->logger = $this->createMock(LoggerInterface::class); $this->container = $this->createMock(ContainerInterface::class); diff --git a/tests/Unit/Service/GebruikSyncServiceDecompositionTest.php b/tests/Unit/Service/GebruikSyncServiceDecompositionTest.php index 65c1df1b..bd210857 100644 --- a/tests/Unit/Service/GebruikSyncServiceDecompositionTest.php +++ b/tests/Unit/Service/GebruikSyncServiceDecompositionTest.php @@ -20,6 +20,7 @@ namespace OCA\SoftwareCatalog\Tests\Unit\Service; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCA\SoftwareCatalog\Service\GebruikSyncService; use OCA\SoftwareCatalog\Service\SettingsService; use PHPUnit\Framework\TestCase; @@ -47,6 +48,7 @@ private function makeService(): GebruikSyncService { new NullLogger(), $this->createMock(SettingsService::class), $this->createMock(ContainerInterface::class), + objectService: $this->createMock(ObjectServiceInterface::class), ); }//end makeService() diff --git a/tests/Unit/Service/IntakeModerationTest.php b/tests/Unit/Service/IntakeModerationTest.php index 3aaf19db..88356e28 100644 --- a/tests/Unit/Service/IntakeModerationTest.php +++ b/tests/Unit/Service/IntakeModerationTest.php @@ -32,6 +32,7 @@ namespace OCA\SoftwareCatalog\Tests\Unit\Service; use OCA\OpenRegister\Db\ObjectEntity; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCA\OpenRegister\Service\ObjectService; use OCA\SoftwareCatalog\Service\IntakeService; use OCA\SoftwareCatalog\Service\ModerationService; @@ -360,10 +361,10 @@ public function testBeoordeelingNonPendingCannotBeApproved(): void { * * @param array $found The search result. * - * @return ObjectService The mock. + * @return ObjectServiceInterface The mock. */ private function objectService(array $found): ObjectService { - $objectService = $this->createMock(ObjectService::class); + $objectService = $this->createMock(ObjectServiceInterface::class); $objectService->method('searchObjects')->willReturn($found); $objectService->method('saveObject')->willReturnCallback( function (array $object) { @@ -380,10 +381,10 @@ function (array $object) { * * @param ObjectEntity $entity The entity find() returns. * - * @return ObjectService The mock. + * @return ObjectServiceInterface The mock. */ private function objectServiceWithFind(ObjectEntity $entity): ObjectService { - $objectService = $this->createMock(ObjectService::class); + $objectService = $this->createMock(ObjectServiceInterface::class); $objectService->method('find')->willReturn($entity); $objectService->method('saveObject')->willReturnCallback( function (array $object) { @@ -411,11 +412,11 @@ private function entity(array $data): ObjectEntity { /** * Build a container resolving the OR ObjectService. * - * @param ObjectService $objectService The OR ObjectService. + * @param ObjectServiceInterface $objectService The OR ObjectService. * * @return ContainerInterface The container. */ - private function container(ObjectService $objectService): ContainerInterface { + private function container(ObjectServiceInterface $objectService): ContainerInterface { $container = $this->createMock(ContainerInterface::class); $container->method('get')->willReturnCallback( function (string $id) use ($objectService) { diff --git a/tests/Unit/Service/MergeOrganisatieServiceTest.php b/tests/Unit/Service/MergeOrganisatieServiceTest.php index 28902d1d..7cba96a5 100644 --- a/tests/Unit/Service/MergeOrganisatieServiceTest.php +++ b/tests/Unit/Service/MergeOrganisatieServiceTest.php @@ -26,7 +26,7 @@ namespace OCA\SoftwareCatalog\Tests\Unit\Service; use OCA\OpenRegister\Db\ObjectEntity; -use OCA\OpenRegister\Service\ObjectService; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCA\SoftwareCatalog\Service\MergeOrganisatieService; use OCA\SoftwareCatalog\Service\OrganisatieService; use OCA\SoftwareCatalog\Service\ProgressTracker; @@ -648,7 +648,7 @@ private function makeService( array $groupMembers, ?IGroupManager $groupManagerOverride = null, ): MergeOrganisatieService { - $objectService = $this->createMock(ObjectService::class); + $objectService = $this->createMock(ObjectServiceInterface::class); $objectService->method('find')->willReturnCallback( function (string|int $id) use ($organisations) { diff --git a/tests/Unit/Service/PortfolioReportServiceTest.php b/tests/Unit/Service/PortfolioReportServiceTest.php index 592c3006..e03bf8c1 100644 --- a/tests/Unit/Service/PortfolioReportServiceTest.php +++ b/tests/Unit/Service/PortfolioReportServiceTest.php @@ -26,7 +26,7 @@ namespace OCA\SoftwareCatalog\Tests\Unit\Service; -use OCA\OpenRegister\Service\ObjectService; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCA\SoftwareCatalog\Service\PortfolioReportDerivation; use OCA\SoftwareCatalog\Service\PortfolioReportService; use OCA\SoftwareCatalog\Service\SettingsService; @@ -340,7 +340,7 @@ public function testAggregateQuadrantsCountsAndSums(): void { public function testBuildReportGebruikAndContractQueriesCarryLimit(): void { $capturedQueries = []; - $objectService = $this->createMock(ObjectService::class); + $objectService = $this->createMock(ObjectServiceInterface::class); $objectService->method('searchObjectsPaginated')->willReturnCallback( function (array $query) use (&$capturedQueries): array { $capturedQueries[] = $query; @@ -417,7 +417,7 @@ function (array $query) use (&$capturedQueries): array { * @return void */ public function testBuildReportDisclosesTruncation(): void { - $objectService = $this->createMock(ObjectService::class); + $objectService = $this->createMock(ObjectServiceInterface::class); $objectService->method('searchObjectsPaginated')->willReturnCallback( function (array $query): array { $schema = $query['@self']['schema'] ?? null; diff --git a/tests/Unit/Service/PublicationServiceTest.php b/tests/Unit/Service/PublicationServiceTest.php index 9be02961..529820ab 100644 --- a/tests/Unit/Service/PublicationServiceTest.php +++ b/tests/Unit/Service/PublicationServiceTest.php @@ -25,6 +25,7 @@ namespace OCA\SoftwareCatalog\Tests\Unit\Service; use OCA\OpenRegister\Db\ObjectEntity; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCA\OpenRegister\Service\ObjectService; use OCA\SoftwareCatalog\Service\PublicationService; use OCA\SoftwareCatalog\Service\SettingsService; @@ -38,9 +39,9 @@ */ class PublicationServiceTest extends TestCase { /** - * @var ObjectService|MockObject + * @var ObjectServiceInterface|MockObject */ - private ObjectService|MockObject $objectService; + private ObjectServiceInterface|MockObject $objectService; /** * @var SettingsService|MockObject @@ -63,7 +64,7 @@ class PublicationServiceTest extends TestCase { private function makeService(array $entryData): PublicationService { $container = $this->createMock(ContainerInterface::class); $this->settings = $this->createMock(SettingsService::class); - $this->objectService = $this->createMock(ObjectService::class); + $this->objectService = $this->createMock(ObjectServiceInterface::class); $logger = $this->createMock(LoggerInterface::class); $this->settings->method('getSchemaIdForObjectType')->willReturn(3); diff --git a/tests/Unit/Service/QueryLimitBoundingTest.php b/tests/Unit/Service/QueryLimitBoundingTest.php index 79bbbeab..fcd37053 100644 --- a/tests/Unit/Service/QueryLimitBoundingTest.php +++ b/tests/Unit/Service/QueryLimitBoundingTest.php @@ -26,6 +26,7 @@ namespace OCA\SoftwareCatalog\Tests\Unit\Service; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCA\OpenRegister\Service\ObjectService; use OCA\SoftwareCatalog\Service\ArchiMateService; use OCA\SoftwareCatalog\Service\FacetService; @@ -62,7 +63,7 @@ class QueryLimitBoundingTest extends TestCase { public function testViewServiceViewIndexQueryCarriesLimit(): void { $capturedQuery = null; - $objectService = $this->createMock(ObjectService::class); + $objectService = $this->createMock(ObjectServiceInterface::class); $objectService->method('searchObjects')->willReturnCallback( function (array $query) use (&$capturedQuery): array { $capturedQuery = $query; @@ -108,7 +109,7 @@ function (array $query) use (&$capturedQuery): array { public function testOrganizationSyncServiceTimeWindowQueryCarriesLimit(): void { $capturedQuery = null; - $objectService = $this->createMock(ObjectService::class); + $objectService = $this->createMock(ObjectServiceInterface::class); $objectService->method('searchObjects')->willReturnCallback( function (array $query) use (&$capturedQuery): array { $capturedQuery = $query; @@ -152,7 +153,7 @@ function (array $query) use (&$capturedQuery): array { public function testFacetServiceBaseObjectQueryCarriesLimit(): void { $capturedQuery = null; - $objectService = $this->createMock(ObjectService::class); + $objectService = $this->createMock(ObjectServiceInterface::class); $objectService->method('searchObjectsPaginated')->willReturnCallback( function (array $query) use (&$capturedQuery): array { $capturedQuery = $query; diff --git a/tests/Unit/Service/ReviewAggregateServiceTest.php b/tests/Unit/Service/ReviewAggregateServiceTest.php index 8239f099..9a5af9f5 100644 --- a/tests/Unit/Service/ReviewAggregateServiceTest.php +++ b/tests/Unit/Service/ReviewAggregateServiceTest.php @@ -23,6 +23,7 @@ namespace OCA\SoftwareCatalog\Tests\Unit\Service; use OCA\OpenRegister\Db\ObjectEntity; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCA\OpenRegister\Service\ObjectService; use OCA\SoftwareCatalog\Service\ReviewAggregateService; use OCA\SoftwareCatalog\Service\SettingsService; @@ -144,10 +145,10 @@ public function testInvalidSubjectTypeRejected(): void { * * @param array $found The search result. * - * @return ObjectService The mock. + * @return ObjectServiceInterface The mock. */ private function objectService(array $found): ObjectService { - $objectService = $this->createMock(ObjectService::class); + $objectService = $this->createMock(ObjectServiceInterface::class); $objectService->method('searchObjects')->willReturn($found); return $objectService; }//end objectService() @@ -169,11 +170,11 @@ private function entity(array $data): ObjectEntity { /** * Build a container resolving the OR ObjectService. * - * @param ObjectService $objectService The OR ObjectService. + * @param ObjectServiceInterface $objectService The OR ObjectService. * * @return ContainerInterface The container. */ - private function container(ObjectService $objectService): ContainerInterface { + private function container(ObjectServiceInterface $objectService): ContainerInterface { $container = $this->createMock(ContainerInterface::class); $container->method('get')->willReturnCallback( function (string $id) use ($objectService) { diff --git a/tests/Unit/Service/ReviewServiceTest.php b/tests/Unit/Service/ReviewServiceTest.php index 92a932be..462b6e27 100644 --- a/tests/Unit/Service/ReviewServiceTest.php +++ b/tests/Unit/Service/ReviewServiceTest.php @@ -28,6 +28,7 @@ namespace OCA\SoftwareCatalog\Tests\Unit\Service; use OCA\OpenRegister\Db\ObjectEntity; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCA\OpenRegister\Service\ObjectService; use OCA\SoftwareCatalog\Service\ReviewService; use OCA\SoftwareCatalog\Service\SettingsService; @@ -277,10 +278,10 @@ public function testEntityUuidReadsAMagicAccessorUuid(): void { * * @param array $found The search result. * - * @return ObjectService The mock. + * @return ObjectServiceInterface The mock. */ private function objectService(array $found): ObjectService { - $objectService = $this->createMock(ObjectService::class); + $objectService = $this->createMock(ObjectServiceInterface::class); $objectService->method('searchObjects')->willReturn($found); $objectService->method('saveObject')->willReturnCallback( function (array $object) { @@ -294,11 +295,11 @@ function (array $object) { /** * Build a container resolving the OR ObjectService. * - * @param ObjectService $objectService The OR ObjectService. + * @param ObjectServiceInterface $objectService The OR ObjectService. * * @return ContainerInterface The container. */ - private function container(ObjectService $objectService): ContainerInterface { + private function container(ObjectServiceInterface $objectService): ContainerInterface { $container = $this->createMock(ContainerInterface::class); $container->method('get')->willReturnCallback( function (string $id) use ($objectService) {