diff --git a/core/lib/Drupal/Core/Entity/EntityViewBuilder.php b/core/lib/Drupal/Core/Entity/EntityViewBuilder.php index 09208a2..cb916a1 100644 --- a/core/lib/Drupal/Core/Entity/EntityViewBuilder.php +++ b/core/lib/Drupal/Core/Entity/EntityViewBuilder.php @@ -9,11 +9,13 @@ use Drupal\Core\Cache\Cache; use Drupal\Core\Entity\Display\EntityViewDisplayInterface; +use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Field\FieldItemInterface; use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Language\Language; use Drupal\Core\Language\LanguageManagerInterface; use Drupal\Core\TypedData\TranslatableInterface; +use Drupal\Core\Render\Element; use Drupal\entity\Entity\EntityViewDisplay; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -138,13 +140,21 @@ protected function getBuildDefaults(EntityInterface $entity, $view_mode, $langco $context = array('langcode' => $langcode); $this->moduleHandler->alter('entity_view_mode', $view_mode, $entity, $context); - $return = array( + $build = array( '#theme' => $this->entityTypeId, - '#pre_render' => array(array($this, 'entityViewBuilderBuildView')), - '#entity' => $entity, + '#pre_render' => array(array($this, 'entityViewBuilderBuildSingle')), "#{$this->entityTypeId}" => $entity, '#view_mode' => $view_mode, '#langcode' => $langcode, + ); + + $build = $this->getBuildCacheDefaults($build, $entity, $view_mode, $langcode); + + return $build; + } + + protected function getBuildCacheDefaults(array $build, EntityInterface $entity, $view_mode, $langcode) { + $build += array( '#cache' => array( 'tags' => array( $this->entityTypeId . '_view' => TRUE, @@ -152,11 +162,10 @@ protected function getBuildDefaults(EntityInterface $entity, $view_mode, $langco ), ) ); - // Cache the rendered output if permitted by the view mode and global entity // type configuration. if ($this->isViewModeCacheable($view_mode) && !$entity->isNew() && $entity->isDefaultRevision() && $this->entityType->isRenderCacheable()) { - $return['#cache'] += array( + $build['#cache'] += array( 'keys' => array( 'entity_view', $this->entityTypeId, @@ -169,11 +178,10 @@ protected function getBuildDefaults(EntityInterface $entity, $view_mode, $langco ); if ($entity instanceof TranslatableInterface && count($entity->getTranslationLanguages()) > 1) { - $return['#cache']['keys'][] = $langcode; + $build['#cache']['keys'][] = $langcode; } } - - return $return; + return $build; } /** @@ -191,8 +199,8 @@ protected function getBuildDefaults(EntityInterface $entity, $view_mode, $langco * * @see drupal_render() */ - public function entityViewBuilderBuildView(array $build) { - $entity = $build['#entity']; + public function entityViewBuilderBuildSingle(array $build) { + $entity = $build["#{$this->entityTypeId}"]; $bundle = $entity->bundle(); $id = $entity->id(); $view_hook = "{$this->entityTypeId}_view"; @@ -229,6 +237,78 @@ public function entityViewBuilderBuildView(array $build) { } /** + * @param array $build + * @return array + */ + public function entityViewBuilderBuildMultiple(array $build) { + // Build the view modes and display objects. + $view_modes = array(); + $langcode = $build['#langcode']; + $entity_type_key = "#{$this->entityTypeId}"; + + // Find the keys for the ContentEntities in the build. + $children = Element::children($build); + $entity_keys = array(); + + foreach($children as $key) { + if (isset($build[$key][$entity_type_key])) { + $entity = $build[$key][$entity_type_key]; + if ($entity instanceof ContentEntityInterface) { + array_push($entity_keys, $key); + } + } + } + + // Store entities for rendering by view_mode. + foreach($entity_keys as $key) { + $view_modes[$build[$key]['#view_mode']][$build[$key][$entity_type_key]->id()] = $entity; + } + + // Build content for the displays represented by the entities. + foreach ($view_modes as $mode => $view_mode_entities) { + $displays[$mode] = EntityViewDisplay::collectRenderDisplays($view_mode_entities, $mode); + $this->buildContent($build, $view_mode_entities, $displays[$mode], $mode, $langcode); + // Remove the single pre_render function from the multiple build items. + foreach (array_keys($view_mode_entities) as $key) { + $pre_render = $build[$key]['#pre_render']; + foreach ($pre_render as $index => $callable) { + if (is_array($callable) && $callable[1] === 'entityViewBuilderBuildSingle') { + unset($build[$key]['#pre_render'][$index]); + } + } + } + } + + $view_hook = "{$this->entityTypeId}_view"; + foreach ($entity_keys as $key) { + $entity = $build[$key][$entity_type_key]; + $view_mode = $build[$key]['#view_mode']; + $display = $displays[$view_mode][$entity->bundle()]; + // Allow for alterations while building, before rendering. + $this->moduleHandler()->invokeAll($view_hook, array(&$build[$key], $entity, $display, $view_mode, $langcode)); + $this->moduleHandler()->invokeAll('entity_view', array(&$build[$key], $entity, $display, $view_mode, $langcode)); + + $this->alterBuild($build[$key], $entity, $display, $view_mode, $langcode); + + // Assign the weights configured in the display. + // @todo: Once https://drupal.org/node/1875974 provides the missing API, + // only do it for 'extra fields', since other components have been taken + // care of in EntityViewDisplay::buildMultiple(). + foreach ($display->getComponents() as $name => $options) { + if (isset($build[$key][$name])) { + $build[$key]['#weight'] = $options['weight']; + } + } + + // Allow modules to modify the render array. + \Drupal::moduleHandler()->alter(array($view_hook, 'entity_view'), $build[$key], $entity, $display); + + } + + return $build; + } + + /** * Specific per-entity building. * * @param array $build @@ -262,16 +342,20 @@ public function viewMultiple(array $entities = array(), $view_mode = 'full', $la $langcode = $this->languageManager->getCurrentLanguage(Language::TYPE_CONTENT)->id; } - $build = array('#sorted' => TRUE); + $build = array( + '#sorted' => TRUE, + '#pre_render' => array(array($this, 'entityViewBuilderBuildMultiple')), + '#langcode' => $langcode, + ); $weight = 0; foreach ($entities as $key => $entity) { // Ensure that from now on we are dealing with the proper translation // object. $entity = $this->entityManager->getTranslationFromContext($entity, $langcode); - // Set defaults for #pre_render. + // Set render defaults. $build[$key] = $this->getBuildDefaults($entity, $view_mode, $langcode); - $entityType = "{$this->entityTypeId}"; + $entityType = $this->entityTypeId; \Drupal::moduleHandler()->alter(array($entityType . '_defaults', 'entity_defaults'), $build[$key], $entity, $view_mode, $langcode); $build[$key]['#weight'] = $weight++; diff --git a/core/modules/comment/lib/Drupal/comment/CommentViewBuilder.php b/core/modules/comment/lib/Drupal/comment/CommentViewBuilder.php index abb698a..74c2ac2 100644 --- a/core/modules/comment/lib/Drupal/comment/CommentViewBuilder.php +++ b/core/modules/comment/lib/Drupal/comment/CommentViewBuilder.php @@ -14,6 +14,8 @@ use Drupal\Core\Entity\EntityManagerInterface; use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Entity\EntityViewBuilder; +use Drupal\entity\Entity\EntityViewDisplay; +use Drupal\Core\Language\Language; use Drupal\Core\Language\LanguageManagerInterface; use Drupal\field\FieldInfo; use Symfony\Component\DependencyInjection\ContainerInterface;