Skip to content
This repository was archived by the owner on May 29, 2026. It is now read-only.

feat: add ObjectServiceMapperAdapter#1335

Merged
bbrands02 merged 9 commits into
developmentfrom
feat/object-service-mapper-adapter
Apr 23, 2026
Merged

feat: add ObjectServiceMapperAdapter#1335
bbrands02 merged 9 commits into
developmentfrom
feat/object-service-mapper-adapter

Conversation

@bbrands02

@bbrands02 bbrands02 commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds ObjectServiceMapperAdapter and the wiring in ObjectService so external apps can obtain a mapper-like interface over OpenRegister objects without depending on ObjectService internals.

Changes

lib/Service/ObjectServiceMapperAdapter.php (new)

Adapter wrapping ObjectService with a mapper-style API. Register and schema context are injected at construction time and applied to every call.

  • find / findByUuid — look up a single object by ID or UUID
  • findAll — list objects with optional filters/pagination config (uses filters.register / filters.schema keys)
  • findAllPaginated — list with pagination via searchObjectsPaginated(), returns results/total/page/pages (uses _register / _schema keys)
  • createFromArray — create object with adapter's register/schema context
  • updateFromArray — PUT (full replace) and PATCH (partial merge) both route through saveObject() with register/schema context; PATCH fetches the existing object via UUID-safe find() before merging
  • update — persist a hydrated ObjectEntity
  • delete — soft-delete by criteria['id']
  • getSchema / getRegister / getValidateHandler

lib/Service/ObjectService.php (additions)

  • getMapper(register, schema) — returns a new ObjectServiceMapperAdapter; non-numeric string arguments (e.g. 'objectEntity' type hints from OpenConnector) produce an unconstrained adapter that searches across all registers/schemas
  • getValidateHandler() — exposes the internal ValidateObject handler
  • clearCurrents() — resets currentRegister, currentSchema, currentObject state

Bug fixes included

  • PATCH broken for UUID identifiers: patchObject() cast the UUID to int via (int) $objectId → 0, so the existing-object lookup always failed. updateFromArray now fetches via UUID-safe find() and merges directly.
  • PUT targeting wrong table: updateObject() called saveObject() without register/schema context. Both PUT and PATCH now go through saveObject() with the adapter's injected context.

Related

Coordinated with openconnector#723 which updates the type hint references in EndpointService.

Test plan

  • POST — create object via OpenConnector endpoint with targetType: register/schema
  • GET single — fetch object by UUID path param
  • GET list — fetch paginated list, verify count/results/next/previous
  • PUT — full replace, verify all fields updated and object stays in correct register/schema table
  • PATCH — partial update with UUID identifier, verify only supplied fields changed
  • DELETE — returns 204, object soft-deleted
  • getMapper('objectEntity')->find($uuid) — unconstrained adapter finds object across all registers

🤖 Generated with Claude Code

Exposes a mapper-like API over ObjectService so external apps (e.g.
OpenConnector) can interact with OpenRegister objects through a familiar
contract without depending on ObjectService internals. Register and
schema context are injected once at construction time.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/openregister @ 91973da

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 147/147
npm ✅ 599/599
PHPUnit ⏭️
Newman ⏭️
Playwright ⏭️

Quality workflow — 2026-04-23 12:07 UTC

Download the full PDF report from the workflow artifacts.

Wires up the ObjectServiceMapperAdapter so external apps can obtain an
instance via ObjectService::getMapper(register, schema).

Changes:
- ObjectService::getMapper() — returns ObjectServiceMapperAdapter with
  injected register/schema context; non-numeric string arguments (e.g.
  'objectEntity' type hints from OpenConnector) are treated as unconstrained
  and produce a register/schema-free adapter that searches globally
- ObjectService::getValidateHandler() — exposes the internal validate handler
- ObjectService::clearCurrents() — resets currentRegister/Schema/Object state
- ObjectServiceMapperAdapter::findAllPaginated() — delegates to
  searchObjectsPaginated() and returns results/total/page/pages

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/openregister @ ac98248

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 147/147
npm ✅ 599/599
PHPUnit ⏭️
Newman ⏭️
Playwright ⏭️

Quality workflow — 2026-04-23 12:28 UTC

Download the full PDF report from the workflow artifacts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/openregister @ 0f0e8ac

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 147/147
npm ✅ 599/599
PHPUnit ⏭️
Newman ⏭️
Playwright ⏭️

Quality workflow — 2026-04-23 12:31 UTC

Download the full PDF report from the workflow artifacts.

Also narrows getValidateHandler() return type from mixed to ValidateObject
and adds the ValidateObject use statement.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/openregister @ dbc96da

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 147/147
npm ✅ 599/599
PHPUnit ⏭️
Newman ⏭️
Playwright ⏭️

Quality workflow — 2026-04-23 12:34 UTC

Download the full PDF report from the workflow artifacts.

…ntext

patchObject() cast the UUID to int via (int) $objectId, breaking PATCH for
UUID-identified objects. updateObject() called saveObject() without the
adapter's register/schema context, targeting the wrong table for PUT.

Both paths now go through saveObject() directly:
- PATCH: fetches existing object via find() (UUID-safe), merges partial data
- PUT: passes full data with id set, register and schema injected

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/openregister @ 0860df1

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 147/147
npm ✅ 599/599
PHPUnit ⏭️
Newman ⏭️
Playwright ⏭️

Quality workflow — 2026-04-23 12:40 UTC

Download the full PDF report from the workflow artifacts.

find() already accepts both IDs and UUIDs. findByUuid was a pure alias
with no additional behaviour, kept only for interface compatibility.
OpenConnector's EndpointService now calls find() directly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@rjzondervan rjzondervan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One question about setting a deprecation message.

Comment thread lib/Service/ObjectServiceMapperAdapter.php Outdated
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/openregister @ eb06f8b

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 147/147
npm ✅ 599/599
PHPUnit ⏭️
Newman ⏭️
Playwright ⏭️

Quality workflow — 2026-04-23 13:07 UTC

Download the full PDF report from the workflow artifacts.

rjzondervan
rjzondervan previously approved these changes Apr 23, 2026
- Add file docblock, constructor docblock, //end markers
- Remove spaces around = in default argument values
- Replace ! operator with === false
- Use named parameter for ValidationException constructor
- Fix ?? alignment spacing
- Add @return void to clearCurrents()
- Remove spaces around = in getMapper() signature

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/openregister @ ecf587e

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 147/147
npm ✅ 599/599
PHPUnit ⏭️
Newman ⏭️
Playwright ⏭️

Quality workflow — 2026-04-23 13:17 UTC

Download the full PDF report from the workflow artifacts.

- Add @author and @license to file comment
- Fix constructor docblock param type alignment
- Remove blank line after class opening brace
- Remove trailing blank lines before }//end class in both files

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/openregister @ 374b714

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 147/147
npm ✅ 599/599
PHPUnit ⏭️
Newman ⏭️
Playwright ⏭️

Quality workflow — 2026-04-23 13:22 UTC

Download the full PDF report from the workflow artifacts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/openregister @ 3cef4e6

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 147/147
npm ✅ 599/599
PHPUnit
Newman
Playwright ⏭️

Quality workflow — 2026-04-23 13:27 UTC

Download the full PDF report from the workflow artifacts.

@bbrands02 bbrands02 merged commit 610a926 into development Apr 23, 2026
16 of 21 checks passed
@bbrands02 bbrands02 deleted the feat/object-service-mapper-adapter branch April 23, 2026 13:38
@WilcoLouwerse

WilcoLouwerse commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

updateFromArray with patch=true can NPE when the object isn't found.

At lib/Service/ObjectServiceMapperAdapter.php L177–L183:

$existing = $this->objectService->find(
    id: (string) $id,
    register: $this->register,
    schema: $this->schema
);
$object = array_merge($existing->getObject(), $object);

ObjectService::find() is declared : ?ObjectEntity (lib/Service/ObjectService.php L571–L578), so a PATCH against a deleted/missing UUID will fatal on $existing->getObject(). Either guard the null case or throw a clear NotFoundException.

@WilcoLouwerse

WilcoLouwerse commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

Unscoped adapters (getMapper('objectEntity')) don't clear stale context between calls.

ObjectService::find() only overwrites current context when the argument is non-null (lib/Service/ObjectService.php L579–L587):

if ($register !== null) { $this->setRegister(register: $register); }
if ($schema !== null)   { $this->setSchema(schema: $schema); }

The adapter's find() (lib/Service/ObjectServiceMapperAdapter.php L51–L58) always passes $this->register / $this->schema — which are null for the unscoped getMapper('objectEntity') path — so currentRegister/currentSchema from a previous call persist.

You added ObjectService::clearCurrents() but the adapter never calls it, so the request-bleed scenario the docstring warns about is still reachable. Either invoke it at the start of each unscoped call, or document loudly that callers must.

@WilcoLouwerse

WilcoLouwerse commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

Minor doc hygiene: the PR description lists find / findByUuid under the adapter's API, but commit 21ab6c6a removed findByUuid.

Current adapter surface only has find() at lib/Service/ObjectServiceMapperAdapter.php L51. Worth syncing the PR body so reviewers aren't looking for a method that no longer exists.

@WilcoLouwerse

WilcoLouwerse commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

getSchema() (L237–L240) and getRegister() (L247–L250) in lib/Service/ObjectServiceMapperAdapter.php cast int|string|nullint:

return $this->schema !== null ? (int) $this->schema : null;

A UUID string would collapse to 0. Not reachable today because ObjectService::getMapper() L3263–L3266 nulls out non-numeric strings before constructing the adapter, but it's a latent footgun — returning the field unchanged (or typing the return as int|string|null) would be safer if a future caller ever threads a UUID through.

@WilcoLouwerse

WilcoLouwerse commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

delete() at lib/Service/ObjectServiceMapperAdapter.php L222–L230 routes straight to deleteObject($uuid) without passing the adapter's register/schema:

return $this->objectService->deleteObject((string) $id);

For an unscoped adapter that's fine, but a scoped adapter arguably shouldn't be able to delete objects that live outside its register/schema — it breaks the "scoped" contract every other method on the adapter upholds. Worth either tightening the check (find-then-verify-scope-then-delete) or documenting the exception.

@WilcoLouwerse

WilcoLouwerse commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

API consistency: the two list methods in lib/Service/ObjectServiceMapperAdapter.php use different key shapes.

findAll() L81–L139 takes register/schema under $config['filters']:

$config['filters']['register'] = $this->register;
$config['filters']['schema']   = $this->schema;

findAllPaginated() L264–L280 takes them as top-level underscore keys:

$requestParams['_register'] = $this->register;
$requestParams['_schema']   = $this->schema;

The docstrings call this out, but it's an easy trap for callers. Worth normalising in a follow-up so both methods accept the same shape.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants