Name dangling prop fields by field type so different-typed prop widgets don't share a TypedData item prototype
Closes #3591918 (closed)
What this MR does
StaticPropSource builds a widget for a component prop from a dangling field item list, and re-parents that field under a host entity so file/image/options widgets can reach the host. TypedDataManager caches field item prototypes keyed by the root object plus the field's path, so every nameless prop field shared one cache slot: the first field type instantiated won it, and a later, differently-typed field got a clone of the wrong item type. Building an integer prop widget before an image prop widget therefore handed the image widget IntegerItems, which crashed the file widget on getUploadLocation().
This names each dangling field after its field type when re-parenting, so the property path disambiguates the cache key: the same field type still shares a prototype, different types no longer collide.
Testing steps
- Run
ddev xb-phpunit tests/src/Kernel/PropShapeRepositoryTest.php. - The new
testDifferentFieldTypeWidgetsDoNotShareItemPrototypebuilds an integer prop widget and then an image prop widget under one host entity, and asserts the image widget builds. It fails before this change (Call to undefined method …\IntegerItem::getUploadLocation()) and passes after.
Notes for reviewers
- Found while working on #3591904: full prop-schema normalization there reorders prop shape discovery, moving the image prop shape after the integer ones, which first exposed this crash. The new test forces that order directly, so it does not depend on discovery order.
- The disambiguator is the field type, not the prop name: the prototype cache maps a key to an item class, and the field type is what determines that class. Same-type fields sharing a prototype is correct; only different types must not collide.
AI usage
The code, test, and this description were drafted with Anthropic's Claude Opus 4.8 (claude-opus-4-8) and reviewed by a human before submission, per Drupal.org's AI contribution policy.