diff --git a/core/modules/views/src/Entity/Render/EntityFieldRenderer.php b/core/modules/views/src/Entity/Render/EntityFieldRenderer.php index d19e105..7dc07b9 100644 --- a/core/modules/views/src/Entity/Render/EntityFieldRenderer.php +++ b/core/modules/views/src/Entity/Render/EntityFieldRenderer.php @@ -124,16 +124,25 @@ public function query(QueryPluginBase $query, $relationship = NULL) { * @see \Drupal\Core\Entity\Entity\EntityViewDisplay */ protected function buildFields(array $values) { - $build = &$this->build; - + $build = []; if ($renderable_fields = $this->getRenderableFieldIds()) { - // Retrieve entity translations to be processed, and group them by bundle. - /** @var \Drupal\Core\Entity\FieldableEntityInterface[][] $entities */ + // Identify all relationships. We will also need one representative field + // for each relationship. + $relationhips = []; + foreach ($renderable_fields as $field_id) { + /** @var \Drupal\views\Plugin\views\field\Field $field */ + $field = $this->view->field[$field_id]; + $relationhips[$field->options['relationship']] = $field; + } + + // For each row, and each relationship in the row, retrieve the entity to + // be processed, and take the correct translation. $entities = []; - $field = $this->view->field[reset($renderable_fields)]; foreach ($values as $result_row) { - $entity = $field->getEntity($result_row); - $entities[$entity->bundle()][$result_row->index] = $this->getEntityTranslation($entity, $result_row); + foreach ($relationhips as $relationhip_id => $field) { + $entity = $field->getEntity($result_row); + $entities[$relationhip_id][$entity->bundle()][$result_row->index] = $this->getEntityTranslation($entity, $result_row); + } } // @todo Note : given the current code in EVD->buildFieldMultiple(), we don't @@ -151,8 +160,9 @@ protected function buildFields(array $values) { /** @var \Drupal\views\Plugin\views\field\Field $field */ $field = $this->view->field[$field_id]; - // Build field render array for each bundle. - foreach ($entities as $bundle => $bundle_entities) { + // Run the formatter across all entities for the field's relationship, + // grouping entities by bundle. + foreach ($entities[$field->options['relationship']] as $bundle => $bundle_entities) { // At this point, we can use the "real" field definition for the bundle // we are rendering. $field_definition = $this->entityManager->getFieldDefinitions($this->getEntityTypeId(), $bundle)[$field->definition['field_name']]; @@ -164,7 +174,7 @@ protected function buildFields(array $values) { } } - + return $build; } /** @@ -206,6 +216,15 @@ protected function getEntityTranslation(EntityInterface $entity, ResultRow $row) } /** + * {@inheritdoc} + */ + public function preRender(array $result) { + // For efficient preRender() populated $this->build with the render arrays for all fields + // in all rows + $this->build = $this->buildFields($result); + } + + /** * Renders entity field data. * * @param \Drupal\views\ResultRow $row @@ -217,26 +236,34 @@ protected function getEntityTranslation(EntityInterface $entity, ResultRow $row) * A renderable array for the entity data contained in the result row. */ public function render(ResultRow $row, Field $field = NULL) { - if (!isset($this->build)) { - $this->buildFields($this->view->result); - } - if (isset($field)) { $field_id = $field->options['id']; - if (!isset($this->build[$row->index][$field_id])) { - $this->buildFields([$row]); + // preRender() initializes $this->build with the render arrays for all + // fields across all rows. We simply pick the one for the row / field we + // are being asked to render, and remove it from $this->build to free + // memory as we progress. + if (isset($this->build[$row->index][$field_id])) { + $build = $this->build[$row->index][$field_id]; + unset($this->build[$row->index][$field_id]); + } + else { + // In the uncommon case where a field gets rendered several times + // (typically through direct Views API calls), the pre-computed render + // array was removed be the unset() above. We the manually rebuild the + // render array for the row. + $build = $this->buildFields([$row])[$row->index][$field_id]; } - $build = $this->build[$row->index][$field_id]; - // Free static cache to save memory. - unset($this->build[$row->index][$field_id]); } else { - if (!isset($this->build[$row->index])) { - $this->buildFields([$row]); + // Same logic as above, in the case where we are being called for a whole + // row. + if (isset($this->build[$row->index])) { + $build = $this->build[$row->index]; + unset($this->build[$row->index]); + } + else { + $build = $this->buildFields([$row])[$row->index]; } - $build = $this->build[$row->index]; - // Free static cache to save memory. - unset($this->build[$row->index]); } return $build;