diff --git a/core/lib/Drupal/Core/Entity/EntityViewBuilder.php b/core/lib/Drupal/Core/Entity/EntityViewBuilder.php index fb19c4e..5231f3a 100644 --- a/core/lib/Drupal/Core/Entity/EntityViewBuilder.php +++ b/core/lib/Drupal/Core/Entity/EntityViewBuilder.php @@ -12,6 +12,7 @@ use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Language\Language; use Drupal\Core\Language\LanguageManagerInterface; +use Drupal\Core\Render\Element; use Symfony\Component\DependencyInjection\ContainerInterface; /** @@ -111,8 +112,9 @@ public function buildContent(array $entities, array $displays, $view_mode, $lang module_invoke_all('entity_prepare_view', $this->entityType, $entities, $displays, $view_mode); foreach ($entities as $entity) { + $entity->content = (!empty($entity->content)) ? $entity->content : array(); // Remove previously built content, if exists. - $entity->content = array( + $entity->content += array( '#view_mode' => $view_mode, ); $entity->content += field_attach_view($entity, $displays[$entity->bundle()], $langcode); @@ -132,18 +134,26 @@ public function buildContent(array $entities, array $displays, $view_mode, $lang * * @return array */ - protected function getBuildDefaults(EntityInterface $entity, $view_mode, $langcode) { - $return = array( + protected function getBuildDefaults(EntityInterface $entity, $view_mode = 'full', $langcode) { + $that = $this; + // Create a closure that uses the current execution context object as its + // invocation object. + $callback = function ($elements) use ($that) { + return $that->entityViewBuilderPreRender($elements); + }; + + $build = array( '#theme' => $this->entityType, "#{$this->entityType}" => $entity, '#view_mode' => $view_mode, '#langcode' => $langcode, + '#pre_render' => array($callback), ); // Cache the rendered output if permitted by the view mode and global entity // type configuration. if ($this->isViewModeCacheable($view_mode) && !$entity->isNew() && !isset($entity->in_preview) && $this->entityInfo->isRenderCacheable()) { - $return['#cache'] = array( + $build['#cache'] = array( 'keys' => array('entity_view', $this->entityType, $entity->id(), $view_mode), 'granularity' => DRUPAL_CACHE_PER_ROLE, 'bin' => $this->cacheBin, @@ -154,7 +164,52 @@ protected function getBuildDefaults(EntityInterface $entity, $view_mode, $langco ); } - return $return; + return $build; + } + + /** + * Performs pre-render tasks on an entity view. + * + * This function is assigned as a #pre_render callback in + * \Drupal\Core\Entity\EntityViewBuilder::getBuildDefaults(). + * + * @param array $elements + * A structured array containing build information and context for an + * entity view. + * + * @see drupal_render() + */ + public function entityViewBuilderPreRender(array $elements) { + $build = $elements; + $entity = $elements['#entity']; + $bundle = $entity->bundle(); + $view_hook = "{$this->entityType}_view"; + $display = $elements['#display']; + $view_mode = $elements['#view_mode']; + $langcode = $elements['#langcode']; + + $entity->content['#view_mode'] = $view_mode; + \Drupal::moduleHandler()->invokeAll($view_hook, array($entity, $display, $view_mode, $langcode)); + \Drupal::moduleHandler()->invokeAll('entity_view', array($entity, $display, $view_mode, $langcode)); + + $this->buildContent(array($entity), array($bundle => $display), $view_mode, $langcode); + + $build += $entity->content; + // We don't need duplicate rendering info in $entity->content. + unset($entity->content); + + $this->alterBuild($build, $entity, $display, $view_mode, $langcode); + + // Assign the weights configured in the display. + foreach ($display->getComponents() as $name => $options) { + if (isset($build[$name])) { + $build[$name]['#weight'] = $options['weight']; + } + } + + // Allow modules to modify the render array. + \Drupal::moduleHandler()->alter(array($view_hook, 'entity_view'), $build, $entity, $display); + return $build; } /** @@ -192,11 +247,12 @@ public function viewMultiple(array $entities = array(), $view_mode = 'full', $la } // Build the view modes and display objects. - $view_modes = array(); - $displays = array(); $context = array('langcode' => $langcode); + $build = array('#sorted' => TRUE); + $view_hook = "{$this->entityType}_view"; + $weight = 0; + foreach ($entities as $key => $entity) { - $bundle = $entity->bundle(); // Ensure that from now on we are dealing with the proper translation // object. @@ -206,46 +262,22 @@ public function viewMultiple(array $entities = array(), $view_mode = 'full', $la // Allow modules to change the view mode. $entity_view_mode = $view_mode; drupal_alter('entity_view_mode', $entity_view_mode, $entity, $context); - // Store entities for rendering by view_mode. - $view_modes[$entity_view_mode][$entity->id()] = $entity; // Get the corresponding display settings. - if (!isset($displays[$entity_view_mode][$bundle])) { - $displays[$entity_view_mode][$bundle] = entity_get_render_display($entity, $entity_view_mode); - } - } - - foreach ($view_modes as $mode => $view_mode_entities) { - $this->buildContent($view_mode_entities, $displays[$mode], $mode, $langcode); - } - - $view_hook = "{$this->entityType}_view"; - $build = array('#sorted' => TRUE); - $weight = 0; - foreach ($entities as $key => $entity) { - $entity_view_mode = isset($entity->content['#view_mode']) ? $entity->content['#view_mode'] : $view_mode; - $display = $displays[$entity_view_mode][$entity->bundle()]; - module_invoke_all($view_hook, $entity, $display, $entity_view_mode, $langcode); - module_invoke_all('entity_view', $entity, $display, $entity_view_mode, $langcode); - - $build[$key] = $entity->content; - // We don't need duplicate rendering info in $entity->content. - unset($entity->content); + $display = entity_get_render_display($entity, $entity_view_mode); + + //$build[$key] = $entity->content; + $build[$key] = array( + '#entity' => $entity, + '#view_mode' => $entity_view_mode, + '#display' => $display, + '#langcode' => $langcode, + ); + // Set defaults for #pre_render. $build[$key] += $this->getBuildDefaults($entity, $entity_view_mode, $langcode); - $this->alterBuild($build[$key], $entity, $display, $entity_view_mode, $langcode); - - // Assign the weights configured in the display. - foreach ($display->getComponents() as $name => $options) { - if (isset($build[$key][$name])) { - $build[$key][$name]['#weight'] = $options['weight']; - } - } $build[$key]['#weight'] = $weight++; - - // Allow modules to modify the render array. - drupal_alter(array($view_hook, 'entity_view'), $build[$key], $entity, $display); } return $build;