chore(Data model): #3591727 Store each prop's translatability per component version so deleting an optional prop keeps config-defined component trees valid

Closes #3591727

Summary

ComponentInputsMapping (introduced in #3582478 (closed)) validates every config-defined component tree's inputs, but it builds each component instance's input schema from the component's live JSON Schema (getMetadata()), not the version the instance actually references. So deleting an optional prop from an SDC or code component — which creates a new component version — made previously valid-and-unchanged config-defined trees (still pointing at the old version) report the removed input as '<prop>' is not a supported key. This is a regression for monolingual sites and a bug for multilingual sites.

Root cause

ComponentInputs::resolveConfigSchemaMapping()JsonSchemaPropsComponentInstanceInputsConfigSchemaGenerator::getConfigSchemaMapping()JsonSchemaPropsComponentSourceBase::getExplicitInputDefinitions()getMetadata(), which can only return the live/deployed schema. The mapping therefore omits props that the referenced version had but the live implementation no longer does.

Approach

Store each prop's translatability in the component version itself:

  • Add an optional translatable boolean to prop_field_definitions (canvas.json_schema_props), computed at discovery. The JSON Schema itself cannot be stored: an array prop's items.meta:enum keys may contain dots, which config keys cannot hold.
  • It is stripped from the component version hash (ComponentSourceBase::generateVersionHash()), so no existing version ids change — it is fully derived from data already hashed (the explicit-input schema and the prop's field type expression).
  • The schema generator now builds the mapping from the versioned prop set, so a removed/changed prop keeps a mapping entry, and uses the stored flag.
  • Backwards compatible: versions saved before this lands have no flag and fall back to recomputing translatability from the live shape (and automatic component-instance updating already repairs instances).
  • The translatability rule is centralized in JsonSchemaPropsComponentSourceBase::isExplicitInputTranslatable().

Testing

  • ddev xb-phpunit tests/src/Kernel/ApiAutoSaveControllerTranslationTest.php
  • ddev xb-phpunit tests/src/Kernel/Plugin/Canvas/ComponentSource/SingleDirectoryComponentTest.php
  • ddev xb-phpunit tests/src/Kernel/Plugin/Canvas/ComponentSource/JsComponentTest.php
  • composer phpcs && composer phpstan
  • Manual: place a config-defined component tree (e.g. a PageRegion) using an SDC/code component with an optional string prop set; remove that prop from the component; confirm the region stays valid (was: '<prop>' is not a supported key).

AI usage disclosure

Per Drupal.org's policy on AI contributions: root-cause analysis, implementation, and test updates were produced with Claude (Opus 4.8) and reviewed by the human contributor before pushing.

Merge request reports

Loading