diff --git a/core/modules/views/src/Entity/Render/EntityFieldRenderer.php b/core/modules/views/src/Entity/Render/EntityFieldRenderer.php index 08ebac2..84e234f 100644 --- a/core/modules/views/src/Entity/Render/EntityFieldRenderer.php +++ b/core/modules/views/src/Entity/Render/EntityFieldRenderer.php @@ -116,7 +116,22 @@ public function query(QueryPluginBase $query, $relationship = NULL) { } /** - * Renders all fields of all rows using entity display objects. + * Builds the render arrays for all fields of all result rows. + * + * The output is built using EntityViewDisplay objects to leverage + * multiple-entity building and ensure a common code path with regular entity + * view. + * - Each entity type in the result set (typically when the View contains + * relationships) is handled separately by separate EntityFieldRenderer + * instances. + * - Each relationship is handled separately, since it operates on its own + * set of entities. + * - Within each relationship, the fields to render are arranged in unique + * sets containing each field at most once (an EntityViewDisplay can + * only process a field once with given display options, but a View can + * contain the same field several times with different display options) + * - For each set of fields, entities are processed by bundle, so that + * formatters can operate on the proper field definition for the bundle. * * @param \Drupal\views\ResultRow[] $values * An array of all ResultRow objects returned from the query. @@ -126,6 +141,8 @@ public function query(QueryPluginBase $query, $relationship = NULL) { protected function buildFields(array $values) { $build = []; if ($values && $renderable_fields = $this->getRenderableFieldIds()) { + $entity_type_id = $this->getEntityTypeId(); + // Group fields by relationship. $fields_by_relationship = []; foreach ($renderable_fields as $field_id) { @@ -134,11 +151,10 @@ protected function buildFields(array $values) { $fields_by_relationship[$field->options['relationship']][$field_id] = $field; } - // Handle each relationship target separately, since they all operate on - // a different set of entities. + // Handle each relationship separately. foreach ($fields_by_relationship as $relationhip_id => $fields) { - // For each result row, collect the entities to display, fetch the right - // translation, and group them by bundle. + // Collect the entities for the relationship, fetch the right + // translation, and group by bundle. $entities_by_bundles = []; $field = current($fields); foreach ($values as $result_row) { @@ -146,34 +162,39 @@ protected function buildFields(array $values) { $entities_by_bundles[$entity->bundle()][$result_row->index] = $this->getEntityTranslation($entity, $result_row); } - // Build "layers" @todo explain - $layers = []; + // Determine unique sets of fields that can be processed by the same + // display. Fields that appear several times in the View open additional + // "overflow" displays. + $display_sets = []; foreach ($fields as $field_id => $field) { $index = 0; - while (isset($layers[$index][$field->definition['field_name']])) { + while (isset($display_sets[$index][$field->definition['field_name']])) { $index++; } - $layers[$index][$field_id] = $field; + $display_sets[$index][$field_id] = $field; } - foreach ($layers as $fields) { + // For each set of fields, build the output by bundle. + foreach ($display_sets as $display_fields) { foreach ($entities_by_bundles as $bundle => $bundle_entities) { - // Create the Display. - $display = new EntityViewDisplay([ - 'targetEntityType' => $this->getEntityTypeId(), + // Create the display, and configure the field display options. + $display = EntityViewDisplay::create([ + 'targetEntityType' => $entity_type_id, 'bundle' => $bundle, 'status' => TRUE, - ], 'entity_view_display'); - foreach ($fields as $field_id => $field) { + ]); + foreach ($display_fields as $field_id => $field) { $display->setComponent($field->definition['field_name'], [ 'type' => $field->options['type'], 'settings' => $field->options['settings'], ]); } - // Let the Display do the rendering. + // Let the display build the render array for the entities. $display_build = $display->buildMultiple($bundle_entities); + // Collect the field render arrays and index them using our internal + // row indexes and field IDs. foreach ($display_build as $row_index => $entity_build) { - foreach ($fields as $field_id => $field) { + foreach ($display_fields as $field_id => $field) { $build[$row_index][$field_id] = $entity_build[$field->definition['field_name']]; } }