core/includes/common.inc | 2 +- core/lib/Drupal/Core/Entity/EntityViewBuilder.php | 113 ++++++++++----------- .../FieldFormatter/CommentDefaultFormatter.php | 1 + .../FieldFormatter/EntityReferenceIdFormatter.php | 5 +- .../EntityReferenceLabelFormatter.php | 5 +- .../Tests/EntityReferenceFormatterTest.php | 1 - .../Plugin/Field/FieldFormatter/LinkFormatter.php | 6 +- .../Entity/Render/DefaultLanguageRenderer.php | 55 ---------- .../Drupal/views/Entity/Render/RendererBase.php | 8 +- 9 files changed, 59 insertions(+), 137 deletions(-) diff --git a/core/includes/common.inc b/core/includes/common.inc index 1e241ca..ea63043 100644 --- a/core/includes/common.inc +++ b/core/includes/common.inc @@ -4002,7 +4002,7 @@ function drupal_render_cache_generate_placeholder($callback, array $context, $to } /** - * Generates a unique token for use in a render cache placeholder. + * Generates a unique token for use in a #post_render_cache placeholder. */ function drupal_render_cache_generate_token() { return \Drupal\Component\Utility\Crypt::randomBytesBase64(55); diff --git a/core/lib/Drupal/Core/Entity/EntityViewBuilder.php b/core/lib/Drupal/Core/Entity/EntityViewBuilder.php index 1240cba..4e0736f 100644 --- a/core/lib/Drupal/Core/Entity/EntityViewBuilder.php +++ b/core/lib/Drupal/Core/Entity/EntityViewBuilder.php @@ -89,6 +89,41 @@ public static function createInstance(ContainerInterface $container, EntityTypeI } /** + * {@inheritdoc} + */ + public function buildContent(array &$build, array $entities, array $displays, $view_mode, $langcode = NULL) { + $entities_by_bundle = array(); + foreach ($entities as $id => $entity) { + // Initialize the field item attributes for the fields being displayed. + // The entity can include fields that are not displayed, and the display + // can include components that are not fields, so we want to act on the + // intersection. However, the entity can have many more fields than are + // displayed, so we avoid the cost of calling $entity->getProperties() + // by iterating the intersection as follows. + foreach ($displays[$entity->bundle()]->getComponents() as $name => $options) { + if ($entity->hasField($name)) { + foreach ($entity->get($name) as $item) { + $item->_attributes = array(); + } + } + } + // Group the entities by bundle. + $entities_by_bundle[$entity->bundle()][$id] = $entity; + } + + // Invoke hook_entity_prepare_view(). + \Drupal::moduleHandler()->invokeAll('entity_prepare_view', array($this->entityTypeId, $entities, $displays, $view_mode)); + + // Let the displays build their render arrays. + foreach ($entities_by_bundle as $bundle => $bundle_entities) { + $display_build = $displays[$bundle]->buildMultiple($bundle_entities); + foreach ($bundle_entities as $id => $entity) { + $build[$id] = array_merge($build[$id], $display_build[$id]); + } + } + } + + /** * Provides entity-specific defaults to the build process. * * @param \Drupal\Core\Entity\EntityInterface $entity @@ -104,7 +139,6 @@ public static function createInstance(ContainerInterface $container, EntityTypeI protected function getBuildDefaults(EntityInterface $entity, $view_mode, $langcode) { $build = array( '#theme' => $this->entityTypeId, - '#pre_render' => array(array($this, 'buildEntity')), "#{$this->entityTypeId}" => $entity, '#view_mode' => $view_mode, '#langcode' => $langcode, @@ -160,7 +194,15 @@ protected function alterBuild(array &$build, EntityInterface $entity, EntityView */ public function view(EntityInterface $entity, $view_mode = 'full', $langcode = NULL) { $buildList = $this->viewMultiple(array($entity), $view_mode, $langcode); - return $buildList[0]; + + // The default ::buildEntityMultiple() #pre_render callback won't run, + // because we extract a child element of the default renderable array. Thus + // we must assign an alternative #pre_render callback that applies the + // necessary transformations and then still calls ::buildEntityMultiple(). + $build = $buildList[0]; + $build['#pre_render'][] = array($this, 'buildEntity'); + + return $build; } /** @@ -187,7 +229,7 @@ public function viewMultiple(array $entities = array(), $view_mode = 'full', $la // Allow modules to change the view mode. $this->moduleHandler->alter('entity_view_mode', $view_mode, $entity, $context); - // Set render defaults. + // Set build defaults. $build[$key] = $this->getBuildDefaults($entity, $view_mode, $langcode); $entityType = $this->entityTypeId; \Drupal::moduleHandler()->alter(array($entityType . '_defaults', 'entity_defaults'), $build[$key], $entity, $view_mode, $langcode); @@ -201,16 +243,15 @@ public function viewMultiple(array $entities = array(), $view_mode = 'full', $la /** * Builds an entity's view; augments entity defaults. * - * This function is assigned as a #pre_render callback in - * \Drupal\Core\Entity\EntityViewBuilder::getBuildDefaults(). + * This function is assigned as a #pre_render callback in ::view(). * - * By delaying the building of an entity until the #pre_render processing in - * drupal_render(), the processing cost of assembling an entity's renderable - * array is saved on cache-hit requests. + * It transforms the renderable array for a single entity to the same + * structure as if we were rendering multiple entities, and then calls the + * default ::buildEntityMultiple() #pre_render callback. * * @param array $build - * A renderable array containing build information and context for an - * entity view. + * A renderable array containing build information and context for an entity + * view. * * @return array * The updated renderable array. @@ -229,11 +270,7 @@ public function buildEntity(array $build) { /** * Builds multiple entities' views; augments entity defaults. * - * This function is assigned as a #pre_render callback in - * \Drupal\Core\Entity\EntityViewBuilder::viewMultiple(). Each entity will - * also have a #pre_render callback in its build array for single building. - * That callback in removed for entities built in this multiple handling - * process so that any entity is only built once. + * This function is assigned as a #pre_render callback in ::viewMultiple(). * * By delaying the building of an entity until the #pre_render processing in * drupal_render(), the processing cost of assembling an entity's renderable @@ -272,17 +309,6 @@ public function buildEntityMultiple(array $build) { $displays = EntityViewDisplay::collectRenderDisplays($view_mode_entities, $view_mode); $this->buildContent($build, $view_mode_entities, $displays, $view_mode, $langcode); foreach (array_keys($view_mode_entities) as $key) { - // Remove the single item pre_render function. The renderable arrays - // were just built in the call to $this->buildContent above. Removing - // the pre_render functions prevents the renderable arrays from being - // built again when drupal_render() recurses into the child elements - // of this list of renderables. - $pre_render = $build[$key]['#pre_render'] ?: array(); - foreach ($pre_render as $index => $callable) { - if (is_array($callable) && $callable[1] === 'buildEntity') { - unset($build[$key]['#pre_render'][$index]); - } - } // Allow for alterations while building, before rendering. $entity = $build[$key][$entity_type_key]; $display = $displays[$entity->bundle()]; @@ -313,41 +339,6 @@ public function buildEntityMultiple(array $build) { /** * {@inheritdoc} */ - public function buildContent(array &$build, array $entities, array $displays, $view_mode, $langcode = NULL) { - $entities_by_bundle = array(); - foreach ($entities as $id => $entity) { - // Initialize the field item attributes for the fields being displayed. - // The entity can include fields that are not displayed, and the display - // can include components that are not fields, so we want to act on the - // intersection. However, the entity can have many more fields than are - // displayed, so we avoid the cost of calling $entity->getProperties() - // by iterating the intersection as follows. - foreach ($displays[$entity->bundle()]->getComponents() as $name => $options) { - if ($entity->hasField($name)) { - foreach ($entity->get($name) as $item) { - $item->_attributes = array(); - } - } - } - // Group the entities by bundle. - $entities_by_bundle[$entity->bundle()][$id] = $entity; - } - - // Invoke hook_entity_prepare_view(). - \Drupal::moduleHandler()->invokeAll('entity_prepare_view', array($this->entityTypeId, $entities, $displays, $view_mode)); - - // Let the displays build their render arrays. - foreach ($entities_by_bundle as $bundle => $bundle_entities) { - $display_build = $displays[$bundle]->buildMultiple($bundle_entities); - foreach ($bundle_entities as $id => $entity) { - $build[$id] = array_merge($build[$id], $display_build[$id]); - } - } - } - - /** - * {@inheritdoc} - */ public function resetCache(array $entities = NULL) { if (isset($entities)) { // Always invalidate the ENTITY_TYPE_list tag. diff --git a/core/modules/comment/lib/Drupal/comment/Plugin/Field/FieldFormatter/CommentDefaultFormatter.php b/core/modules/comment/lib/Drupal/comment/Plugin/Field/FieldFormatter/CommentDefaultFormatter.php index 432c06e..154edf6 100644 --- a/core/modules/comment/lib/Drupal/comment/Plugin/Field/FieldFormatter/CommentDefaultFormatter.php +++ b/core/modules/comment/lib/Drupal/comment/Plugin/Field/FieldFormatter/CommentDefaultFormatter.php @@ -247,4 +247,5 @@ public function settingsSummary() { } return array(); } + } diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/Field/FieldFormatter/EntityReferenceIdFormatter.php b/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/Field/FieldFormatter/EntityReferenceIdFormatter.php index c20038f..6d4c28d 100644 --- a/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/Field/FieldFormatter/EntityReferenceIdFormatter.php +++ b/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/Field/FieldFormatter/EntityReferenceIdFormatter.php @@ -44,10 +44,7 @@ public function viewElements(FieldItemListInterface $items) { // that the referenced entity is deleted, the cache for referring // entities must be cleared. '#cache' => array( - 'tags' => array( - $referenced_entity->getEntityTypeID() => $referenced_entity->id(), - $referenced_entity->getEntityTypeID() . '_view' => TRUE, - ), + 'tags' => $referenced_entity->getCacheTag(), ), ); } diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/Field/FieldFormatter/EntityReferenceLabelFormatter.php b/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/Field/FieldFormatter/EntityReferenceLabelFormatter.php index b7157c9..bc305cd 100644 --- a/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/Field/FieldFormatter/EntityReferenceLabelFormatter.php +++ b/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/Field/FieldFormatter/EntityReferenceLabelFormatter.php @@ -79,10 +79,7 @@ public function viewElements(FieldItemListInterface $items) { else { $elements[$delta] = array('#markup' => check_plain($label)); } - $elements[$delta]['#cache']['tags'] = array( - $referenced_entity->getEntityTypeID() => $referenced_entity->id(), - $referenced_entity->getEntityTypeID() . '_view' => TRUE, - ); + $elements[$delta]['#cache']['tags'] = $referenced_entity->getCacheTag(); } } diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceFormatterTest.php b/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceFormatterTest.php index 00140cc..5bbf52c 100644 --- a/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceFormatterTest.php +++ b/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceFormatterTest.php @@ -117,6 +117,5 @@ public function testIdFormatter() { $this->assertEqual($build[0]['#markup'], $entity_1->id(), format_string('The markup returned by the @formatter formatter is correct.', array('@formatter' => $formatter))); $this->assertEqual($build[0]['#cache']['tags'][$this->entityType], $entity_1->id(), format_string('The @formatter formatter assigned the correct cache tag entity ID.', array('@formatter' => $formatter))); - $this->assertTrue($build[0]['#cache']['tags'][$this->entityType . '_view'], format_string('The @formatter formatter assigned the correct value for the entity type view cache tag.', array('@formatter' => $formatter))); } } diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Field/FieldFormatter/LinkFormatter.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Field/FieldFormatter/LinkFormatter.php index fd2c277..856b73e 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Field/FieldFormatter/LinkFormatter.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Field/FieldFormatter/LinkFormatter.php @@ -52,11 +52,7 @@ public function viewElements(FieldItemListInterface $items) { unset($item->_attributes); } - $elements[$delta]['#cache']['tags'] = array( - 'taxonomy_term' => $item->entity->id(), - 'taxonomy_term_view' => TRUE, - ); - + $elements[$delta]['#cache']['tags'] = $item->entity->getCacheTag(); } } diff --git a/core/modules/views/lib/Drupal/views/Entity/Render/DefaultLanguageRenderer.php b/core/modules/views/lib/Drupal/views/Entity/Render/DefaultLanguageRenderer.php index 8bd9e94..18875f5 100644 --- a/core/modules/views/lib/Drupal/views/Entity/Render/DefaultLanguageRenderer.php +++ b/core/modules/views/lib/Drupal/views/Entity/Render/DefaultLanguageRenderer.php @@ -15,61 +15,6 @@ class DefaultLanguageRenderer extends RendererBase { /** - * {@inheritdoc} - */ - public function preRender(array $result) { - /** @var \Drupal\Core\Entity\ContentEntityInterface[] $entities */ - $entities = array(); - $langcodes = array(); - - /** @var \Drupal\views\ResultRow $row */ - foreach ($result as $row) { - $entity = $row->_entity; - $entity->view = $this->view; - $langcodes[] = $langcode = $this->getLangcode($row); - $entities[$entity->id()][$langcode] = $entity; - } - $count_langcodes = count(array_unique($langcodes)); - - $view_builder = $this->view->rowPlugin->entityManager->getViewBuilder($this->entityType->id()); - - if ($count_langcodes > 1) { - // Render each entity separate if we do have more than one translation. - // @todo It should be possible to use viewMultiple even if you get - // more than one language. See https://drupal.org/node/2073217. - foreach ($entities as $entity_translation) { - foreach ($entity_translation as $langcode => $entity) { - $entity = $entity->getTranslation($langcode); - $this->build[$entity->id()][$langcode] = $view_builder->view($entity, $this->view->rowPlugin->options['view_mode'], $langcode); - } - } - } - else { - $langcode = reset($langcodes); - $entity_translations = array(); - foreach ($entities as $entity_translation) { - $entity = $entity_translation[$langcode]; - $entity_translations[$entity->id()] = $entity->hasTranslation($langcode) ? $entity->getTranslation($langcode) : $entity; - } - $this->build = $view_builder->viewMultiple($entity_translations, $this->view->rowPlugin->options['view_mode'], $langcode); - } - } - - /** - * {@inheritdoc} - */ - public function render(ResultRow $row) { - $entity_id = $row->_entity->id(); - $langcode = $this->getLangcode($row); - if (isset($this->build[$entity_id][$langcode])) { - return $this->build[$entity_id][$langcode]; - } - else { - return $this->build[$entity_id]; - } - } - - /** * Returns the language code associated to the given row. * * @param \Drupal\views\ResultRow $row diff --git a/core/modules/views/lib/Drupal/views/Entity/Render/RendererBase.php b/core/modules/views/lib/Drupal/views/Entity/Render/RendererBase.php index a3b211f..b3590c2 100644 --- a/core/modules/views/lib/Drupal/views/Entity/Render/RendererBase.php +++ b/core/modules/views/lib/Drupal/views/Entity/Render/RendererBase.php @@ -67,18 +67,14 @@ public function query(QueryPluginBase $query) { * The full array of results from the query. */ public function preRender(array $result) { - /** @var \Drupal\Core\Entity\ContentEntityInterface[] $entities */ - $entities = array(); + $view_builder = $this->view->rowPlugin->entityManager->getViewBuilder($this->entityType->id()); /** @var \Drupal\views\ResultRow $row */ foreach ($result as $row) { $entity = $row->_entity; $entity->view = $this->view; - $entities[$entity->id()] = $entity; + $this->build[$entity->id()] = $view_builder->view($entity, $this->view->rowPlugin->options['view_mode'], $this->getLangcode($row)); } - - $view_builder = $this->view->rowPlugin->entityManager->getViewBuilder($this->entityType->id()); - $this->build = $view_builder->viewMultiple($entities, $this->view->rowPlugin->options['view_mode']); } /**