Problem/Motivation

EntityReferenceRevisionsFieldItemList::referencedEntities loads the referenced entities by revision id from the database instead of using the existing entities on the reference item. This leads to potential data loss if the referenced entity has a change compared to the database.

Proposed resolution

This was implemented based on EntityReferenceFieldItemList::referencedEntities but there are two fundamental differences a) there's no static cache for revision list loads which means the object on the entity property will differ from what load returns -- for plain entity references the load will return the handle of an object in the memory cache b) there's no point because there's no loadMultiple for revisions. The whole method should be collapsed into

foreach ($this->list as $delta => $item) {
  if ($item->entity) {
    $target_entities[$delta] = $item->entity;
  }
}
return $target_entities;

and be done. This will actually be faster in many cases because the EntityReferenceRevisions / entity_revision_reference data type plugin optimizes getTarget().

Remaining tasks

User interface changes

API changes

Data model changes

Release notes snippet

Comments

Charlie ChX Negyesi created an issue. See original summary.

ghost of drupal past’s picture

Issue summary: View changes
ghost of drupal past’s picture

Priority: Normal » Critical

Data loss bugs are critical.

ghost of drupal past’s picture

Issue summary: View changes
ghost of drupal past’s picture

Issue summary: View changes
ghost of drupal past’s picture

Issue summary: View changes
berdir’s picture

Thanks for reporting. This will also help with #3095329: Optimise entity reference autocomplete widget loading referencable entities

I have some ideas on how it could be improved further, like doing a loadMultiple() first but yes, if we don't have a isLoaded() or something on ->entity then that's also a bit of overhead.

+1 to just simplifying it to that.

super_romeo’s picture

Yes.

    $entities = [];
    foreach ($fieldItemList as $delta => $item) {
      if ($item->entity) {
        $entities[$delta] = $item->entity;
      }
    }

returns correct data,

but

    $entities = $fieldItemList->referencedEntities();

returns wrong data.

spadxiii’s picture

StatusFileSize
new641 bytes

Here's a small patch with a less-intrusive fix than the proposed solution. I've added the entity-check in the existing code.

I didn't check if the proposed solution works in all cases. My patch seems to fix the problems for me, but I'm unsure if the rest of the code can be removed here.

travis-bradbury’s picture

StatusFileSize
new1.44 KB

This patch is the change described in the issue summary - replacing the whole function with just $item->entity for each item.

travis-bradbury’s picture

Status: Active » Needs review
travis-bradbury’s picture

StatusFileSize
new1.47 KB

Oops, #10 has a typo.

vpowner’s picture

Regarding data loss, I noticed this function does not account for orphaned references. The ER on a node that points to a no longer existing node needs to be reported (or exception thrown) so we can investigate/fix.

mstrelan’s picture

I came across this working on a ConstraintValidator on an entity that checked the value of a field inside a paragraphs item on the entity. This was previously only able to access the saved revision of the paragraphs item, and not the revision about to be saved. I tested #12 for this use case and it's working correctly.

berdir’s picture

Status: Needs review » Fixed

Tests would be nice for the actual regression, but the change makes sense and passes the existing tests.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.