diff --git a/core/lib/Drupal/Core/Entity/EntityViewBuilder.php b/core/lib/Drupal/Core/Entity/EntityViewBuilder.php index 7b29c93..5883eea 100644 --- a/core/lib/Drupal/Core/Entity/EntityViewBuilder.php +++ b/core/lib/Drupal/Core/Entity/EntityViewBuilder.php @@ -61,6 +61,15 @@ class EntityViewBuilder extends EntityHandlerBase implements EntityHandlerInterf protected $languageManager; /** + * The EntityViewDisplay objects created for individual field rendering. + * + * @see \Drupal\Core\Entity\EntityViewBuilder::getSingleFieldDisplay() + * + * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface[] + */ + protected $singleFieldDisplays; + + /** * Constructs a new EntityViewBuilder. * * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type @@ -393,25 +402,11 @@ protected function isViewModeCacheable($view_mode) { * {@inheritdoc} */ public function viewField(FieldItemListInterface $items, $display_options = array()) { - $output = array(); $entity = $items->getEntity(); $field_name = $items->getFieldDefinition()->getName(); + $display = $this->getSingleFieldDisplay($entity, $field_name, $display_options); - // Get the display object. - if (is_string($display_options)) { - $view_mode = $display_options; - $display = EntityViewDisplay::collectRenderDisplay($entity, $view_mode); - // Hide all fields except the current one. - foreach (array_keys($entity->getFieldDefinitions()) as $name) { - if ($name != $field_name) { - $display->removeComponent($name); - } - } - } - else { - $display = $this->getCustomViewModeDisplay($entity, $field_name, $display_options); - } - + $output = array(); $build = $display->build($entity); if (isset($build[$field_name])) { $output = $build[$field_name]; @@ -421,38 +416,6 @@ public function viewField(FieldItemListInterface $items, $display_options = arra } /** - * Returns a display using the _custom view mode. - * - * This method maintains a cache of display objects to reduce the number - * created when rendering fields individually, for cases such as views tables. - * The cache is keyed by bundle, field name, and display options. - * - * @param \Drupal\Core\Entity\EntityInterface $entity - * @param string $field_name - * @param array $display_options - * - * @return \Drupal\Core\Entity\Display\EntityViewDisplayInterface - */ - protected function getCustomViewModeDisplay($entity, $field_name, array $display_options) { - $target_type = $entity->getEntityTypeId(); - $bundle = $entity->bundle(); - $key = $target_type . $bundle . $field_name . crc32(serialize($display_options)); - - if (!isset($this->viewDisplays[$key])) { - $view_mode = '_custom'; - $this->viewDisplays[$key] = entity_create('entity_view_display', array( - 'targetEntityType' => $entity->getEntityTypeId(), - 'bundle' => $entity->bundle(), - 'mode' => $view_mode, - 'status' => TRUE, - )); - $this->viewDisplays[$key]->setComponent($field_name, $display_options); - } - - return $this->viewDisplays[$key]; - } - - /** * {@inheritdoc} */ public function viewFieldItem(FieldItemInterface $item, $display = array()) { @@ -476,4 +439,52 @@ public function viewFieldItem(FieldItemInterface $item, $display = array()) { return $output; } + /** + * Returns the Display to use for rendering an individual field with viewField(). + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity. + * @param string $field_name + * The field name. + * @param string|array $display_options + * The display options passed to the viewField() method. + * + * @return \Drupal\Core\Entity\Display\EntityViewDisplayInterface + */ + protected function getSingleFieldDisplay($entity, $field_name, array $display_options) { + if (is_string($display_options)) { + // View mode: use the Display configured for the view mode. + $view_mode = $display_options; + $display = EntityViewDisplay::collectRenderDisplay($entity, $view_mode); + // Hide all fields except the current one. + foreach (array_keys($entity->getFieldDefinitions()) as $name) { + if ($name != $field_name) { + $display->removeComponent($name); + } + } + } + else { + // Array of custom display options: use a runtime Display for the + // '_custom' view mode. Persist the displays created, to reduce the number + // of objects (displays and formatter plugins) created when rendering a + // series of fields individually for cases such as views tables + $entity_type = $entity->getEntityTypeId(); + $bundle = $entity->bundle(); + $key = $entity_type . ':' . $bundle . ':' . $field_name . ':' . crc32(serialize($display_options)); + if (!isset($this->singleFieldDisplays[$key])) { + $view_mode = '_custom'; + $this->singleFieldDisplays[$key] = entity_create('entity_view_display', array( + 'targetEntityType' => $entity_type, + 'bundle' => $bundle, + 'mode' => $view_mode, + 'status' => TRUE, + )); + $this->singleFieldDisplays[$key]->setComponent($field_name, $display_options); + } + $display = $this->singleFieldDisplays[$key]; + } + + return $display; + } + } diff --git a/core/lib/Drupal/Core/Entity/EntityViewBuilderInterface.php b/core/lib/Drupal/Core/Entity/EntityViewBuilderInterface.php index 27a1c87..c3e167a 100644 --- a/core/lib/Drupal/Core/Entity/EntityViewBuilderInterface.php +++ b/core/lib/Drupal/Core/Entity/EntityViewBuilderInterface.php @@ -106,7 +106,7 @@ public function resetCache(array $entities = NULL); * * @param \Drupal\Core\Field\FieldItemListInterface $items * FieldItemList containing the values to be displayed. - * @param array $display_options + * @param string|array $display_options * Can be either: * - The name of a view mode. The field will be displayed according to the * display settings specified for this view mode in the $field @@ -137,7 +137,7 @@ public function viewField(FieldItemListInterface $items, $display_options = arra * * @param \Drupal\Core\Field\FieldItemInterface $item * FieldItem to be displayed. - * @param array $display_options + * @param string|array $display_options * Can be either the name of a view mode, or an array of display settings. * See EntityViewBuilderInterface::viewField() for more information. *