Component transforms need to be per sourceType, not per component prop

Created on 26 March 2025, 7 days ago

Overview

Discovered in πŸ“Œ Split model values into resolved and raw Active

We currently store model values like so

'href' => [
        'sourceType' => 'static:field_item:link',
        'sourceTypeSettings' => [
          'instance' => [
            'title' => 0,
          ],
        ],
        'value' => ['uri' => 'https://drupal.org'],
        'expression' => 'β„ΉοΈŽlink␟uri',
      ]

But after data has been stored, prop shape matching can be modified by installing new modules/field types.
And the representation of the data in the component config entity can change.

Steps to reproduce

  1. Install a test site using XBTestSetp - eg
     php ./core/scripts/test-site.php install --setup-file "/data/app/modules/experience_builder/tests/src/TestSite/XBTestSetup.php" --install-profile "nightwatch_testing"  --base-url http://nginx:8080 --db-url mysql://local:local@nginx/local --json
    
  2. Inspect the my-hero component shapes
    drush cget experience_builder.component.sdc.experience_builder.my-hero
    

    and note that the href is stored as a link

    cta1href:
          field_type: link
          field_storage_settings: {  }
          field_instance_settings:
            title: 0
          field_widget: link_default
          default_value:
            uri: 'https://example.com'
            options: {  }
          expression: β„ΉοΈŽlink␟uri
    
  3. Edit node 1 (created by XBTestSetup) in XB and note that the href value doesn't get updated
  4. Add a new Hero to that page and note that the URL is editable
  5. Enable the xb_test_storage_prop_shape_alter module and re-inspect the config entity
    cta1href:
          field_type: uri
          field_storage_settings: {  }
          field_instance_settings: {  }
          field_widget: uri
          default_value:
            value: 'https://example.com'
          expression: β„ΉοΈŽuri␟value
    

    - note that it has now changed to a URI consistent with the stored data

  6. Revisit node 1 in XB and note you can now edit the link href of original Hero but not that of the new one

This happens because we store the transforms in the component list and these are drawn from the config entity.
But the data shape stored for a given component depends on the sourceType at the time it was created. This is important because <the sourceType can change the data stored. For example in this case a link item has multiple columns so is stored as ['uri' => 'https://example.com'] whilst a uri item only has a single value and is stored as 'https://example.com'. This means we have to respect the stored sourceType because the value matches it.
In the frontend this manifests as having the wrong transforms. The link item has a specific Link transform whilst the uri only uses the MainPropertyName transform. Because we're looking at the current component as the source of transforms, we're getting the wrong one depending on when the data was stored.

Proposed resolution

Instead of keeping transforms in the component list under the field data for each prop, send a list of transforms per source type in drupalSettings or an API and use the sourceType (which we have available) in the clientside code to find the transforms to apply based on the stored sourceType rather than the current one

User interface changes

πŸ› Bug report
Status

Active

Version

0.0

Component

Redux-integrated field widgets

Created by

πŸ‡¦πŸ‡ΊAustralia larowlan πŸ‡¦πŸ‡ΊπŸ.au GMT+10

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @larowlan
  • πŸ‡¦πŸ‡ΊAustralia larowlan πŸ‡¦πŸ‡ΊπŸ.au GMT+10
  • πŸ‡¦πŸ‡ΊAustralia larowlan πŸ‡¦πŸ‡ΊπŸ.au GMT+10
  • πŸ‡¦πŸ‡ΊAustralia larowlan πŸ‡¦πŸ‡ΊπŸ.au GMT+10

    πŸ“Œ Split model values into resolved and raw Active needs to go in first because without that we always use the sourceType from the config entity

  • πŸ‡¦πŸ‡ΊAustralia larowlan πŸ‡¦πŸ‡ΊπŸ.au GMT+10
  • πŸ‡§πŸ‡ͺBelgium wim leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί

    But after data has been stored, prop shape matching can be modified by installing new modules/field types.
    And the representation of the data in the component config entity can change.

    But that only dictates the field type + widget to use for new component instances.

    All existing component instances do NOT change. That's why all that information (field type + storage settings + instance settings + widget) is self-contained in the \Drupal\experience_builder\PropSource\StaticPropSource and stored for every prop of every instance of every SDC-like component.

    @lauriii once created an issue with a mock-up many months ago, early during the life of XB, to indicate what he thought the UX should be to allow the content creator to "update" to the new default StaticPropSource for an SDC prop.

    Instead of keeping transforms in the component list under the field data for each prop, send a list of transforms per source type in drupalSettings or an API and use the sourceType (which we have available) in the clientside code to find the transforms to apply based on the stored sourceType rather than the current one

    Ahhhh … πŸ™ˆ So this is about

        "transforms": {
          "text": {
            "mainProperty": [
              
            ]
          }
    

    And not about StaticPropSources and what data they contain β€” it's about those two getting out of sync! IOW: this is a bug we unwittingly introduced in πŸ“Œ Move clientside assumptions about prop form data shape into a series of prop specific transforms Active πŸ˜¬πŸ™ˆ

    +1 for this being stable-blocking. But shouldn't it be per widget instead of "per sourceType"?

  • πŸ‡§πŸ‡ͺBelgium wim leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί
  • πŸ‡§πŸ‡ͺBelgium wim leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί
Production build 0.71.5 2024