fix(import): eager magic-table creation for every schema (closes #1615)#1616
Merged
Conversation
`ImportHandler::importFromApp` previously called
`MagicMapper::ensureTableForRegisterSchema` only from inside the
seed-objects loop (line 3187, formerly 3174). Schemas with an empty
seed-objects array therefore never got their per-schema magic table
provisioned during register import.
The fallback was lazy: the first write against the schema would trigger
`ensureTableForRegisterSchema` inside `MagicMapper::saveObject`. For
entity-style schemas (source, job, mapping, …) users write to them
directly so the table appears on first use. For **log-style schemas**
(call_log, job_log, synchronization_log, synchronization_contract_log
in ConductionNL/openconnector — and similar in other apps) writes only
happen from internal services. If anything earlier in the chain
swallowed an error (controller validation, find lookup, etc.), the
service never reached saveObject and the table stayed missing forever.
In practice: openconnector dashboards rendered empty even after
thousands of Newman + Playwright invocations because every
`POST /sources/test/{id}` 404'd at the controller (separate bug,
ConductionNL/openconnector#840), AND if it ever reached CallService
the saveObject would have thrown `relation oc_openregister_table_65_223
does not exist`.
## Fix
Provision the magic table for **every** Schema bound to the Register
inside `autoCreateRegisterIfApplication()`, right after the Register
is created / reconciled and its Configuration is synced. The loop
iterates the schemas already in scope, is idempotent (the underlying
helper short-circuits when the table already exists per
MagicTableHandler line 109-112), and non-fatal (any per-schema
failure logs a warning instead of aborting the whole import).
The original seed-objects-loop pre-create at line 3225 stays in place
as a defensive no-op for back-compat.
## Verified end-to-end on a chain-E openconnector instance
occ maintenance:repair --include-expensive
→ OpenConnector Repair step fires importFromApp
→ autoCreateRegisterIfApplication runs the new loop
→ All 15 openconnector schemas now have magic tables:
source / job / mapping / synchronization (entity)
call_log / job_log / synchronization_log /
synchronization_contract_log (log — previously missing)
… plus 7 others.
CallService->call() then succeeds and writes to call_log.
Contributor
Quality Report — ConductionNL/openregister @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ❌ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ❌ | ||||
| stylelint | ❌ | ||||
| composer | ❌ | ✅ 162/162 | |||
| npm | ✅ | ✅ 532/532 | |||
| PHPUnit | ⏭️ | ||||
| Newman | ⏭️ | ||||
| Playwright | ⏭️ |
Quality workflow — 2026-05-21 18:41 UTC
Download the full PDF report from the workflow artifacts.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #1615.
ImportHandler::importFromApppreviously calledMagicMapper::ensureTableForRegisterSchema()only from inside the seed-objects loop (line 3187 in the old layout). Schemas without seed data — typically log-style schemas likecall_log,job_log,synchronization_log,synchronization_contract_log— therefore never got theiroc_openregister_table_{registerId}_{schemaId}table during register import.The fallback (lazy-create on first
saveObject) only fires when a service runs end-to-end. If anything earlier in the chain swallows an error, the table stays missing forever and the dashboard reads zero.Reproduction (and verified fix)
On a chain-E openconnector instance with
feature/i18n-complete-translations+ Repair step:Before fix:
After fix +
occ maintenance:repair --include-expensive:Subsequent
CallService::call()then succeeds and the call_log row is queryable viaGET /api/objects/openregister/api/objects/openconnector/call_log(after a separate owner-attribution step — see #1617 below).What changed
autoCreateRegisterIfApplication()(already runs for anyx-openregister.type=applicationdescriptor) gains a per-schema loop right after the Register row is created/reconciled and the Configuration's registers[] is synced. The loop iterates the existing$schemasparameter, is idempotent (MagicTableHandler::ensureTableForRegisterSchemashort-circuits when the table exists, line 109-112), and per-schema-non-fatal (a failure logs a warning + continues).The pre-existing seed-objects-loop pre-create (formerly at line 3187, now ~3225) stays as a defensive no-op for back-compat.
Out of scope (filed as follow-ups during this investigation)
x-openregister-archivalannotation is silently stripped by the vocabulary check. Logs aren't immutable + retention rules don't run._owner, which then get filtered out of REST list queries even for admin — needs an opt-in "system-owned" flag or auto-attribution to the source's owner.call_log.sourceId+event_message.eventId|consumerId|subscriptionIdwere typedinteger(chain-A leftovers); should bestring format=uuid. Filing on openconnector side.Test plan