- π§πͺBelgium dieterholvoet Brussels
EntityReferenceFieldItemList::referencedEntities should just call $this->getValue($include_computed=TRUE) and then from the result leave only the entity objects.
Drupal\Core\TypedData\Plugin\DataType\ItemList::getValue()
doesn't have an$include_computed
parameter, so that option is off the table.I'll create a MR implementing the first option.
- Merge request !3761Issue #2826717: EntityReferenceFieldItemList::referencedEntities might not return up-to-date entity objects β (Open) created by dieterholvoet
- πΊπΈUnited States smustgrave
There are 2 options it appears in the issue summary proposed solution. Can it be highlighted which was chosen?
Also could use a test case showing the issue.
- π§πͺBelgium dieterholvoet Brussels
It seems like the current implementation of the MR causes a performance problem.
$item->entity !== NULL
triggersDataReferenceBase::getValue()
, which triggersEntityReference::getTarget()
, which triggersEntityStorageInterface::load()
. This means that every entity is now loaded separately. I'll look for a different solution. - π§πͺBelgium dieterholvoet Brussels
I found a fix. In a custom API endpoint with a bunch of
referencedEntities()
calls this makes a huge performance difference: -5.62 s (-75%) and -2 219 database queries. Hopefully anyone using a patch from this issue sees this. - π¨πSwitzerland berdir Switzerland
Yes, that's the problem with accessing the property, it auto-initializes, so that condition is always true if it can be loaded.
I don't think your change is correct either. getValue() will never return computed values, so the result is the same as HEAD.
I don't think it is possible at all to do this, because even accessing the EntityReference property directly with get('entity') there simply is no API to detect whether it has been set or not. There is no public method to access $this->target and \Drupal\Core\Entity\Plugin\DataType\EntityReference::getTarget() always loads it if not set, that's the same as ->entity.
That's why \Drupal\Core\Field\Plugin\Field\FieldFormatter\EntityReferenceFormatterBase::prepareView + \Drupal\Core\Field\Plugin\Field\FieldFormatter\EntityReferenceFormatterBase::getEntitiesToView() use the magic _loaded property to track that.
So to change this, we'd first need to extend the underlying entity reference property to add a method to check if the refernce is loaded or not.
- π§πͺBelgium dieterholvoet Brussels
I don't think your change is correct either. getValue() will never return computed values, so the result is the same as HEAD.
No, that does seem to work. Because
EntityReferenceItem::getValue()
looks like this:/** * {@inheritdoc} */ public function getValue() { $values = parent::getValue(); // If there is an unsaved entity, return it as part of the field item values // to ensure idempotency of getValue() / setValue(). if ($this->hasNewEntity()) { $values['entity'] = $this->entity; } return $values; }
$this->entity
also triggersEntityReference::getTarget()
, but sinceisset($this->target)
it doesn't trigger a new entity load and returns the existing entity object instead.I think that means that the previous approach would have also worked, if we had just replaced
$item->entity !== NULL
with$item->hasNewEntity()
. - π§πͺBelgium dieterholvoet Brussels
By the way, I just tested this with code like this:
$this->set('field_event_type', [EventType::create()]); $types = $this->get('field_event_type')->referencedEntities();
$types
contained the newly created, unsaved entity.