feat(Data model): #3591678 Coalesce reference fields consumed only through nested objects

Follow-up to !1112 (merged) (notes 1200321 / 1200324).

What

When a reference field has no directly-picked value and multiple references descend through it into the same bundle on different final fields, Coalescer::coalesce() merges them into one reference-only FieldObjectPropsExpression:

ℹ︎␜entity:node:article␝uid␞␟{mail↝entity␜␜entity:user␝mail␞␟value,name↝entity␜␜entity:user␝name␞␟value}

buildReferencePayload() descends such objects, so the runtime payload is identical to the separate references (a nested entity object with __type) — a storage normalization, not a behavior change. The SameFieldMustBeCoalesced validator flags the un-coalesced form.

Testing

  • composer run phpunit -- tests/src/Unit/CoalescerTest.php
  • composer run phpunit -- tests/src/Kernel/Entity/JavaScriptComponentUpdateFromClientSideTest.php
  • composer run phpunit -- tests/src/Kernel/Config/JavaScriptComponentValidationTest.php
  • composer run phpunit -- tests/src/Kernel/Plugin/Canvas/ComponentSource/JsComponentTest.php --filter testContentEntityReference
  • composer run lint (PHPCS + PHPStan)

AI usage

Implemented with Claude Code (Claude Opus 4.8). Human-reviewed.

Edited by Christian López Espínola

Merge request reports

Loading