From fa1b5ba5984ac3afa10d9db56c56491232199d44 Mon Sep 17 00:00:00 2001 From: Alex Pott <alex.a.pott@googlemail.com> Date: Mon, 3 Nov 2014 08:39:33 +0000 Subject: [PATCH] Issue #2346763 by yched, msonnabaum: Improve views field rendering performance by caching entity display objects. --- .../Drupal/Core/Entity/EntityViewBuilder.php | 82 +++++++++++++------ .../Entity/EntityViewBuilderInterface.php | 4 +- .../field/src/Plugin/views/field/Field.php | 4 - 3 files changed, 60 insertions(+), 30 deletions(-) diff --git a/core/lib/Drupal/Core/Entity/EntityViewBuilder.php b/core/lib/Drupal/Core/Entity/EntityViewBuilder.php index 8330590f2494..a6688f42794d 100644 --- a/core/lib/Drupal/Core/Entity/EntityViewBuilder.php +++ b/core/lib/Drupal/Core/Entity/EntityViewBuilder.php @@ -9,13 +9,13 @@ use Drupal\Core\Cache\Cache; use Drupal\Core\Entity\Display\EntityViewDisplayInterface; +use Drupal\Core\Entity\Entity\EntityViewDisplay; use Drupal\Core\Field\FieldItemInterface; use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Language\LanguageInterface; use Drupal\Core\Language\LanguageManagerInterface; use Drupal\Core\TypedData\TranslatableInterface; use Drupal\Core\Render\Element; -use Drupal\Core\Entity\Entity\EntityViewDisplay; use Symfony\Component\DependencyInjection\ContainerInterface; /** @@ -60,6 +60,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. * @@ -393,32 +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 { - $view_mode = '_custom'; - $display = entity_create('entity_view_display', array( - 'targetEntityType' => $entity->getEntityTypeId(), - 'bundle' => $entity->bundle(), - 'mode' => $view_mode, - 'status' => TRUE, - )); - $display->setComponent($field_name, $display_options); - } - + $output = array(); $build = $display->build($entity); if (isset($build[$field_name])) { $output = $build[$field_name]; @@ -451,4 +439,50 @@ public function viewFieldItem(FieldItemInterface $item, $display = array()) { return $output; } + /** + * Returns an EntityViewDisplay for rendering an individual field. + * + * @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, $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_id = $entity->getEntityTypeId(); + $bundle = $entity->bundle(); + $key = $entity_type_id . ':' . $bundle . ':' . $field_name . ':' . crc32(serialize($display_options)); + if (!isset($this->singleFieldDisplays[$key])) { + $this->singleFieldDisplays[$key] = EntityViewDisplay::create(array( + 'targetEntityType' => $entity_type_id, + 'bundle' => $bundle, + 'mode' => '_custom', + 'status' => TRUE, + ))->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 27a1c8793c8e..c3e167a01351 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. * diff --git a/core/modules/field/src/Plugin/views/field/Field.php b/core/modules/field/src/Plugin/views/field/Field.php index c05f6edf5bb9..6cb97ba45d87 100644 --- a/core/modules/field/src/Plugin/views/field/Field.php +++ b/core/modules/field/src/Plugin/views/field/Field.php @@ -740,10 +740,6 @@ public function getItems(ResultRow $values) { 'type' => $this->options['type'], 'settings' => $this->options['settings'], 'label' => 'hidden', - // Pass the View object in the display so that fields can act on it. - 'views_view' => $this->view, - 'views_field' => $this, - 'views_row_id' => $values->index, ); $render_array = $entity->get($this->definition['field_name'])->view($display); -- GitLab