|
26 | 26 | use Psr\Container\ContainerInterface; |
27 | 27 | use Psr\Log\LoggerInterface; |
28 | 28 | use OCA\OpenRegister\Contract\ObjectServiceInterface; |
29 | | -use OCA\OpenRegister\Db\SchemaMapper; |
30 | | -use OCA\OpenRegister\Db\RegisterMapper; |
31 | | -use OCA\OpenRegister\Service\Object\SaveObject\MetadataHydrationHandler; |
32 | 29 |
|
33 | 30 | /** |
34 | 31 | * Syncs user profile changes to the corresponding contactpersoon object. |
@@ -58,16 +55,10 @@ class UserProfileUpdatedEventListener implements IEventListener { |
58 | 55 | * |
59 | 56 | * @param ContainerInterface $container DI container for lazy service resolution. |
60 | 57 | * @param ObjectServiceInterface $objectService OpenRegister object access (ADR-084 contract). |
61 | | - * @param SchemaMapper $schemaMapper Resolves the contactpersoon schema. |
62 | | - * @param RegisterMapper $registerMapper Resolves the register the schema lives in. |
63 | | - * @param MetadataHydrationHandler $metadataHydrationHandler Hydrates `@self` metadata on read. |
64 | 58 | */ |
65 | 59 | public function __construct( |
66 | 60 | private readonly ContainerInterface $container, |
67 | 61 | private readonly ObjectServiceInterface $objectService, |
68 | | - private readonly SchemaMapper $schemaMapper, |
69 | | - private readonly RegisterMapper $registerMapper, |
70 | | - private readonly MetadataHydrationHandler $metadataHydrationHandler, |
71 | 62 | ) { |
72 | 63 | }//end __construct() |
73 | 64 |
|
@@ -207,16 +198,16 @@ private function syncToContactPerson(UserProfileUpdatedEvent $event, LoggerInter |
207 | 198 | ] |
208 | 199 | ); |
209 | 200 |
|
210 | | - // Merge the patch into existing data and save directly via mapper to skip schema validation. |
211 | | - // Schema validation can reject existing data with legacy values (e.g. notificaties enum). |
| 201 | + // Merge the patch into the existing payload. `saveObject()` is |
| 202 | + // PUT-semantic, so the FULL payload must be carried forward, not only |
| 203 | + // the changed keys. Validation is skipped on the save because schema |
| 204 | + // validation can reject pre-existing legacy values (e.g. notificaties |
| 205 | + // enum) that this listener never touched. |
212 | 206 | $mergedObject = array_merge($contactData, $patch); |
213 | | - $contactPerson->setObject($mergedObject); |
214 | 207 |
|
215 | 208 | $this->persistContactPersonPatch( |
216 | 209 | contactPerson: $contactPerson, |
217 | | - register: (int)$register, |
218 | | - schema: (int)$contactPersonSchema, |
219 | | - logger: $logger |
| 210 | + object: $mergedObject |
220 | 211 | ); |
221 | 212 |
|
222 | 213 | $logger->info( |
@@ -278,63 +269,39 @@ private function buildContactPatch( |
278 | 269 | }//end buildContactPatch() |
279 | 270 |
|
280 | 271 | /** |
281 | | - * Persist the patched contactpersoon entity, regenerating `_name` |
282 | | - * metadata first when the schema is loadable. |
| 272 | + * Persist the patched contactpersoon payload through the published |
| 273 | + * OpenRegister contract. |
283 | 274 | * |
284 | | - * @param object $contactPerson The contactpersoon entity. |
285 | | - * @param int $register The voorzieningen register id. |
286 | | - * @param int $schema The contactpersoon schema id. |
287 | | - * @param LoggerInterface $logger Logger for hydration warnings. |
| 275 | + * `_name` metadata is NOT regenerated here. This method used to load the |
| 276 | + * schema through `SchemaMapper` and call |
| 277 | + * `MetadataHydrationHandler::hydrateObjectMetadata()` itself — both of them |
| 278 | + * OpenRegister internals that ADR-084's published contract deliberately does |
| 279 | + * not expose, and neither of which a leaf app can load in its own unit |
| 280 | + * tests. It was also redundant: `ObjectService::saveObject()` calls |
| 281 | + * `hydrateObjectMetadata()` on both its create and its update path before |
| 282 | + * handing the entity to `objectEntityMapper`, so the hydration happens |
| 283 | + * exactly once either way — it was simply being done twice, one layer too |
| 284 | + * deep. |
| 285 | + * |
| 286 | + * @param object $contactPerson The contactpersoon entity (read for its coordinates). |
| 287 | + * @param array $object The full merged payload to store (PUT-semantic). |
288 | 288 | * |
289 | 289 | * @return void |
290 | 290 | */ |
291 | 291 | private function persistContactPersonPatch( |
292 | 292 | object $contactPerson, |
293 | | - int $register, |
294 | | - int $schema, |
295 | | - LoggerInterface $logger, |
| 293 | + array $object, |
296 | 294 | ): void { |
297 | | - $schemaEntity = null; |
298 | | - $registerEntity = null; |
299 | | - try { |
300 | | - $schemaEntity = $this->schemaMapper->find(id: $schema, _rbac: false, _multitenancy: false); |
301 | | - $registerEntity = $this->registerMapper->find(id: $register, _rbac: false, _multitenancy: false); |
302 | | - } catch (\Exception $e) { |
303 | | - $logger->warning( |
304 | | - '[UserProfileUpdatedEventListener] Could not load schema/register entities for _name hydration', |
305 | | - [ |
306 | | - 'error' => $e->getMessage(), |
307 | | - ] |
308 | | - ); |
309 | | - } |
310 | | - |
311 | | - if ($schemaEntity !== null) { |
312 | | - $this->metadataHydrationHandler->hydrateObjectMetadata(entity: $contactPerson, schema: $schemaEntity); |
313 | | - $logger->debug( |
314 | | - '[UserProfileUpdatedEventListener] Regenerated _name metadata', |
315 | | - [ |
316 | | - 'newName' => $contactPerson->getName(), |
317 | | - ] |
318 | | - ); |
319 | | - } |
320 | | - |
321 | | - // Persist through the published contract rather than OpenRegister's Db |
322 | | - // layer. The comment this replaces worried that a plain save would touch |
323 | | - // "just the blob table" — it does not: ObjectService::saveObject() calls |
324 | | - // metaHydrationHandler->hydrateObjectMetadata() and then |
325 | | - // objectEntityMapper->update(entity:, register:, schema:), which IS the |
326 | | - // magic-mapper route. This listener was hand-rolling OpenRegister's own |
327 | | - // save pipeline, one layer too deep. |
328 | 295 | $this->objectService->saveObject( |
329 | | - object: $contactPerson->getObject(), |
| 296 | + object: $object, |
330 | 297 | register: $contactPerson->getRegister(), |
331 | 298 | schema: $contactPerson->getSchema(), |
332 | 299 | uuid: $contactPerson->getUuid(), |
333 | 300 | silent: true, |
334 | 301 | _validation: false |
335 | 302 | ); |
336 | 303 |
|
337 | | - }//end persistContactpersoonPatch() |
| 304 | + }//end persistContactPersonPatch() |
338 | 305 |
|
339 | 306 | /** |
340 | 307 | * Find a contactpersoon by username, falling back to a case-insensitive email search. |
|
0 commit comments