Add ComponentSourceInterface::getReferencedEntities

Created on 7 July 2025, about 18 hours ago

Overview

Default content exports needs to know if a field item references another entity so it can resolve a dependency graph.
Prop sources can reference entities but there is no way to retrieve that information when you have a ComponentTreeItem

Proposed resolution

Add ComponentSourceInterface::getReferenceEntities and have each source plugin implement it. Most likely only JS and SDC will return something, based on the use of an entity-reference field in the prop sources

User interface changes

✨ Feature request
Status

Active

Version

0.0

Component

Component sources

Created by

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

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

Merge Requests

Comments & Activities

  • Issue created by @larowlan
  • πŸ‡§πŸ‡ͺBelgium wim leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί

    have each source plugin implement it

    I'm confused by this. Block components never reference other entities? An SDC can never reference content entities?

    It's not the component itself that can reference other (content) entities, but only the inputs for the component.

    So then what you need is to call \Drupal\experience_builder\Plugin\DataType\ComponentInputs::getPropSources() and add some logic around that to filter down to only content dependencies?

    IOW: a sibling to \Drupal\experience_builder\Plugin\DataType\ComponentInputs::getPropSourcesWithDependency() (which was added in πŸ› Component trees with dynamic prop sources that introspect field values don't add the relevant fields to their dependencies Active ), to get just the content dependencies?

    IOW … \Drupal\experience_builder\Plugin\DataType\ComponentInputs::calculateDependencies(), but filtered down to content dependencies? Which is already tested by \Drupal\Tests\experience_builder\Kernel\DataType\ComponentInputsDependenciesTest::testCalculateDependencies():

        // Verify content dependencies if we have a valid entity.
        $file_entity = $hero_reference->get('field_media_image')->entity;
        assert($file_entity instanceof File);
        $file_uuid = $file_entity->get('uuid')->value;
        self::assertSame([
          'module' => [
    βœ‚βœ‚βœ‚
          ],
          'config' => [
    βœ‚βœ‚βœ‚
          ],
          'content' => [
            'file:file:' . $file_uuid,
          ],
        ], $item_list->get(3)->get('inputs')->calculateDependencies($node));
    
  • πŸ‡§πŸ‡ͺBelgium wim leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί

    I know @phenaproxima asked about this in chat, that's why @larowlan opened this.

    So let's get him unblocked by providing a test, should be simple :)

  • πŸ‡§πŸ‡ͺBelgium wim leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί

    Test coverage pushed.

    I used \Drupal\experience_builder\Plugin\Field\FieldType\ComponentTreeItem::calculateFieldItemValueDependencies() to also allow for the case of anything else besides the explicit inputs of a component instance (the inputs property) to declare content dependencies.

    (I could have used $item->get('inputs')->calculateDependencies($node)['content']) instead of $item->calculateFieldItemValueDependencies($node)['content'], but this just seemed more prudent because truly all-encompassing all dependencies of the component instance/ComponentTreeItem.)

    And in doing so … this revealed a bug in \Drupal\experience_builder\Plugin\DataType\ComponentInputs: it should've been implementing ContentAwareDependentInterface, not DependentPluginInterface, because that is the difference between calculateFieldItemValueDependencies() executing either of these 2 branches:

          if ($property instanceof DependentPluginInterface) {
            $dependencies = NestedArray::mergeDeep($dependencies, $property->calculateDependencies());
          }
          elseif ($property instanceof ContentAwareDependentInterface) {
            $dependencies = NestedArray::mergeDeep($dependencies, $property->calculateDependencies($host_entity));
          }
    

    πŸ˜…

    Yay for tests exercising what we say/think should work. Here's hoping there's no additional bug discoveries…

  • Pipeline finished with Failed
    about 5 hours ago
    #541738
  • πŸ‡§πŸ‡ͺBelgium wim leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί
  • πŸ‡§πŸ‡ͺBelgium wim leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί
  • Pipeline finished with Success
    about 3 hours ago
    #541761
  • πŸ‡ΊπŸ‡ΈUnited States phenaproxima Massachusetts

    For the record, this blocks site templates. Or at least, site templates that ship XB-ified content (which is likely to be all site templates).

    The reason this blocks site templates is because default content (including xb_page entities) needs to be able to calculate its dependencies. Without a method to get the referenced entities in an XB component tree, the default content exporter will have no way to do that.

  • πŸ‡§πŸ‡ͺBelgium wim leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί
    1. […] would indeed be most helpful.

      I'm sure that would be for that particular use case. But it's a single use case. And this works, doesn't it? So are you really not unblocked?

    2. I bet that ideally, you'd actually be able to just call \Drupal\Core\Entity\ContentEntityBase::referencedEntities() and that'd automatically take care of XB fields' reliance on other entities?

      And that's actually totally doable too, we'd just add a new references computed property to \Drupal\experience_builder\Plugin\Field\FieldType\ComponentTreeItem::propertyDefinitions(). But that's not something we should A) rush, B) delay beta for.

    So can you please confirm that this MR (point 1) would unblock you for now? Then I'd be happy to merge it right away, and we can keep this issue open (to implement point 2). πŸ˜ŠπŸ™

  • πŸ‡ΊπŸ‡ΈUnited States phenaproxima Massachusetts

    I have not tested this (I need that damn default content exporter in core first!) but here's my inference from reading the code in HEAD and the MR...

    If this results in content dependencies being added to the field item like node:page:SOME_UUID, that will be enough data to give the exporter what it needs. This appears to be confirmed by the test coverage.

    So in the interest of acceleration, I'm calling this one ready.

  • Pipeline finished with Skipped
    about 2 hours ago
    #542005
  • Pipeline finished with Skipped
    about 2 hours ago
    #542006
  • Pipeline finished with Skipped
    about 2 hours ago
    #542007
  • πŸ‡§πŸ‡ͺBelgium wim leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί

    Merged & rescoped for #9.2 πŸ‘

  • πŸ‡§πŸ‡ͺBelgium wim leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί

    Still needs clarifications on what exactly is needed though β€” probably best after is done? 😊

  • πŸ‡ΊπŸ‡ΈUnited States phenaproxima Massachusetts

    I don't think the component tree field type should need to provide another property at all.

    The content exporter is currently leaning towards allowing modules to supply callback functions that know how to handle specific field/data types. So in fact, XB would have an event subscriber like this pseudocode:

    $event->setCallback('component_tree', function (ComponentTreeItem $item, ExportMetadata $metadata): array {
      foreach ($item->referencedEntities() as $referenced) {
        $metadata->addDependency($referenced);
      }
    });
    
  • πŸ‡§πŸ‡ͺBelgium wim leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί

    The content exporter is currently leaning towards

    πŸ‘

    Looked through your post history and found ✨ Add a command-line utility to export content in YAML format Active , which seems to be what this is for?

  • πŸ‡ΊπŸ‡ΈUnited States phenaproxima Massachusetts

    That's the one!

Production build 0.71.5 2024