Skip to content
Snippets Groups Projects
Commit 9c88b1af authored by catch's avatar catch
Browse files

Issue #2090509 by yched, swentel, Wim Leers: Optimize...

Issue #2090509 by yched, swentel, Wim Leers: Optimize entity_get_render_display() for the case of 'multiple entity view'.
parent 51d9879c
Branches
Tags
2 merge requests!7452Issue #1797438. HTML5 validation is preventing form submit and not fully...,!789Issue #3210310: Adjust Database API to remove deprecated Drupal 9 code in Drupal 10
...@@ -569,62 +569,6 @@ function entity_get_display($entity_type, $bundle, $view_mode) { ...@@ -569,62 +569,6 @@ function entity_get_display($entity_type, $bundle, $view_mode) {
return $display; return $display;
} }
/**
* Returns the entity view display used to render an entity.
*
* Depending on the configuration of the view mode for the bundle, this can be
* either the display object associated to the view mode, or the 'default'
* display.
*
* This function should only be used internally when rendering an entity. When
* assigning suggested display options for a component in a given view mode,
* entity_get_display() should be used instead, in order to avoid inadvertently
* modifying the output of other view modes that might happen to use the
* 'default' display too. Those options will then be effectively applied only
* if the view mode is configured to use them.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity being rendered.
* @param string $view_mode
* The view mode being rendered.
*
* @return \Drupal\Core\Entity\Display\EntityViewDisplayInterface
* The entity view display that should be used to render the entity.
*
* @see entity_get_display().
*/
function entity_get_render_display(EntityInterface $entity, $view_mode) {
$entity_type = $entity->getEntityTypeId();
$bundle = $entity->bundle();
$render_view_mode = 'default';
// Fall back to the default display if the display for the view mode does
// not exist or is disabled.
if ($view_mode != 'default') {
$ids = array(
'default' => $entity_type . '.' . $bundle . '.default',
$view_mode => $entity_type . '.' . $bundle . '.' . $view_mode,
);
$entity_displays = entity_load_multiple('entity_view_display', $ids);
if (isset($entity_displays[$ids[$view_mode]]) && $entity_displays[$ids[$view_mode]]->status()) {
$render_view_mode = $view_mode;
}
}
$display = entity_get_display($entity_type, $bundle, $render_view_mode);
$display->originalMode = $view_mode;
// Let modules alter the display.
$display_context = array(
'entity_type' => $entity_type,
'bundle' => $bundle,
'view_mode' => $view_mode,
);
drupal_alter('entity_view_display', $display, $display_context);
return $display;
}
/** /**
* Returns the entity form display associated to a bundle and form mode. * Returns the entity form display associated to a bundle and form mode.
* *
...@@ -681,59 +625,6 @@ function entity_get_form_display($entity_type, $bundle, $form_mode) { ...@@ -681,59 +625,6 @@ function entity_get_form_display($entity_type, $bundle, $form_mode) {
return $entity_form_display; return $entity_form_display;
} }
/**
* Returns the entity form display used to render an entity form.
*
* This function should only be used internally when rendering an entity form.
* When assigning suggested form display options for a component in a given form
* mode, entity_get_form_display() should be used instead, in order to avoid
* inadvertently modifying the output of other form modes that might happen to
* use the 'default' form display too. Those options will then be effectively
* applied only if the form mode is configured to use them.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity for which the form is being rendered.
* @param string $form_mode
* The form mode being rendered.
*
* @return \Drupal\Core\Entity\Display\EntityFormDisplayInterface
* The entity form display object that should be used to render the entity
* form.
*
* @see entity_get_form_display().
*/
function entity_get_render_form_display(EntityInterface $entity, $form_mode) {
$entity_type = $entity->getEntityTypeId();
$bundle = $entity->bundle();
$render_form_mode = 'default';
// Look at the default form display and form display for the view mode, and
// fallback to the former if the latter does not exist is disabled.
if ($form_mode != 'default') {
$ids = array(
'default' => $entity_type . '.' . $bundle . '.default',
$form_mode => $entity_type . '.' . $bundle . '.' . $form_mode,
);
$entity_form_displays = entity_load_multiple('entity_form_display', $ids);
if (isset($entity_form_displays[$ids[$form_mode]]) && $entity_form_displays[$ids[$form_mode]]->status()) {
$render_form_mode = $form_mode;
}
}
$form_display = entity_get_form_display($entity_type, $bundle, $render_form_mode);
$form_display->originalMode = $form_mode;
// Let modules alter the form display.
$form_display_context = array(
'entity_type' => $entity_type,
'bundle' => $bundle,
'form_mode' => $form_mode,
);
drupal_alter('entity_form_display', $form_display, $form_display_context);
return $form_display;
}
/** /**
* Generic access callback for entity pages. * Generic access callback for entity pages.
* *
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
use Drupal\Core\Entity\Display\EntityFormDisplayInterface; use Drupal\Core\Entity\Display\EntityFormDisplayInterface;
use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormBase;
use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\entity\Entity\EntityFormDisplay;
/** /**
* Base class for entity form controllers. * Base class for entity form controllers.
...@@ -121,7 +122,7 @@ protected function init(array &$form_state) { ...@@ -121,7 +122,7 @@ protected function init(array &$form_state) {
// Prepare the entity to be presented in the entity form. // Prepare the entity to be presented in the entity form.
$this->prepareEntity(); $this->prepareEntity();
$form_display = entity_get_render_form_display($this->entity, $this->getOperation()); $form_display = EntityFormDisplay::collectRenderDisplay($this->entity, $this->getOperation());
$this->setFormDisplay($form_display, $form_state); $this->setFormDisplay($form_display, $form_state);
// Invoke the prepare form hooks. // Invoke the prepare form hooks.
......
...@@ -9,9 +9,9 @@ ...@@ -9,9 +9,9 @@
use Drupal\Core\Cache\Cache; use Drupal\Core\Cache\Cache;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface; use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Language\Language; use Drupal\Core\Language\Language;
use Drupal\Core\Language\LanguageManagerInterface; use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\entity\Entity\EntityViewDisplay;
use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ContainerInterface;
/** /**
...@@ -193,7 +193,6 @@ public function viewMultiple(array $entities = array(), $view_mode = 'full', $la ...@@ -193,7 +193,6 @@ public function viewMultiple(array $entities = array(), $view_mode = 'full', $la
// Build the view modes and display objects. // Build the view modes and display objects.
$view_modes = array(); $view_modes = array();
$displays = array();
$context = array('langcode' => $langcode); $context = array('langcode' => $langcode);
foreach ($entities as $key => $entity) { foreach ($entities as $key => $entity) {
$bundle = $entity->bundle(); $bundle = $entity->bundle();
...@@ -208,14 +207,10 @@ public function viewMultiple(array $entities = array(), $view_mode = 'full', $la ...@@ -208,14 +207,10 @@ public function viewMultiple(array $entities = array(), $view_mode = 'full', $la
drupal_alter('entity_view_mode', $entity_view_mode, $entity, $context); drupal_alter('entity_view_mode', $entity_view_mode, $entity, $context);
// Store entities for rendering by view_mode. // Store entities for rendering by view_mode.
$view_modes[$entity_view_mode][$entity->id()] = $entity; $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) { foreach ($view_modes as $mode => $view_mode_entities) {
$displays[$mode] = EntityViewDisplay::collectRenderDisplays($view_mode_entities, $mode);
$this->buildContent($view_mode_entities, $displays[$mode], $mode, $langcode); $this->buildContent($view_mode_entities, $displays[$mode], $mode, $langcode);
} }
......
...@@ -7,13 +7,14 @@ ...@@ -7,13 +7,14 @@
namespace Drupal\edit\Form; namespace Drupal\edit\Form;
use Drupal\Core\Form\FormBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityStorageControllerInterface; use Drupal\Core\Entity\EntityStorageControllerInterface;
use Drupal\Core\Entity\EntityChangedInterface;
use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Form\FormBase;
use Drupal\entity\Entity\EntityFormDisplay;
use Drupal\user\TempStoreFactory; use Drupal\user\TempStoreFactory;
use Drupal\Core\Entity\EntityChangedInterface; use Symfony\Component\DependencyInjection\ContainerInterface;
/** /**
* Builds and process a form for editing a single entity field. * Builds and process a form for editing a single entity field.
...@@ -128,7 +129,7 @@ protected function init(array &$form_state, EntityInterface $entity, $field_name ...@@ -128,7 +129,7 @@ protected function init(array &$form_state, EntityInterface $entity, $field_name
// @todo Allow the usage of different form modes by exposing a hook and the // @todo Allow the usage of different form modes by exposing a hook and the
// UI for them. // UI for them.
$form_state['form_display'] = entity_get_render_form_display($entity, 'default'); $form_state['form_display'] = EntityFormDisplay::collectRenderDisplay($entity, 'default');
} }
/** /**
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Field\FieldItemListInterface;
use Drupal\edit\Access\EditEntityFieldAccessCheckInterface; use Drupal\edit\Access\EditEntityFieldAccessCheckInterface;
use Drupal\field\FieldInstanceInterface; use Drupal\entity\Entity\EntityViewDisplay;
/** /**
* Generates in-place editing metadata for an entity field. * Generates in-place editing metadata for an entity field.
...@@ -78,7 +78,7 @@ public function generateFieldMetadata(FieldItemListInterface $items, $view_mode) ...@@ -78,7 +78,7 @@ public function generateFieldMetadata(FieldItemListInterface $items, $view_mode)
} }
// Early-return if no editor is available. // Early-return if no editor is available.
$formatter_id = entity_get_render_display($entity, $view_mode)->getRenderer($field_name)->getPluginId(); $formatter_id = EntityViewDisplay::collectRenderDisplay($entity, $view_mode)->getRenderer($field_name)->getPluginId();
$editor_id = $this->editorSelector->getEditor($formatter_id, $items); $editor_id = $this->editorSelector->getEditor($formatter_id, $items);
if (!isset($editor_id)) { if (!isset($editor_id)) {
return array('access' => FALSE); return array('access' => FALSE);
......
...@@ -35,6 +35,83 @@ class EntityFormDisplay extends EntityDisplayBase implements EntityFormDisplayIn ...@@ -35,6 +35,83 @@ class EntityFormDisplay extends EntityDisplayBase implements EntityFormDisplayIn
*/ */
protected $displayContext = 'form'; protected $displayContext = 'form';
/**
* Returns the entity_form_display object used to build an entity form.
*
* Depending on the configuration of the form mode for the entity bundle, this
* can be either the display object associated to the form mode, or the
* 'default' display.
*
* This method should only be used internally when rendering an entity form.
* When assigning suggested display options for a component in a given form
* mode, entity_get_form_display() should be used instead, in order to avoid
* inadvertently modifying the output of other form modes that might happen to
* use the 'default' display too. Those options will then be effectively
* applied only if the form mode is configured to use them.
*
* hook_entity_form_display_alter() is invoked on each display, allowing 3rd
* party code to alter the display options held in the display before they are
* used to generate render arrays.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity for which the form is being built.
* @param string $form_mode
* The form mode.
*
* @return \Drupal\Core\Entity\Display\EntityFormDisplayInterface
* The display object that should be used to build the entity form.
*
* @see entity_get_form_display()
* @see hook_entity_form_display_alter()
*/
public static function collectRenderDisplay($entity, $form_mode) {
$entity_type = $entity->getEntityTypeId();
$bundle = $entity->bundle();
// Check the existence and status of:
// - the display for the form mode,
// - the 'default' display.
if ($form_mode != 'default') {
$candidate_ids[] = $entity_type . '.' . $bundle . '.' . $form_mode;
}
$candidate_ids[] = $entity_type . '.' . $bundle . '.default';
$results = \Drupal::entityQuery('entity_form_display')
->condition('id', $candidate_ids)
->condition('status', TRUE)
->execute();
// Load the first valid candidate display, if any.
$storage = \Drupal::entityManager()->getStorageController('entity_form_display');
foreach ($candidate_ids as $candidate_id) {
if (isset($results[$candidate_id])) {
$display = $storage->load($candidate_id);
break;
}
}
// Else create a fresh runtime object.
if (empty($display)) {
$display = $storage->create(array(
'targetEntityType' => $entity_type,
'bundle' => $bundle,
'mode' => $form_mode,
'status' => TRUE,
));
}
// Let the display know which form mode was originally requested.
$display->originalMode = $form_mode;
// Let modules alter the display.
$display_context = array(
'entity_type' => $entity_type,
'bundle' => $bundle,
'form_mode' => $form_mode,
);
\Drupal::moduleHandler()->alter('entity_form_display', $display, $display_context);
return $display;
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
namespace Drupal\entity\Entity; namespace Drupal\entity\Entity;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface; use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\entity\EntityDisplayBase; use Drupal\entity\EntityDisplayBase;
...@@ -35,6 +36,131 @@ class EntityViewDisplay extends EntityDisplayBase implements EntityViewDisplayIn ...@@ -35,6 +36,131 @@ class EntityViewDisplay extends EntityDisplayBase implements EntityViewDisplayIn
*/ */
protected $displayContext = 'view'; protected $displayContext = 'view';
/**
* Returns the display objects used to render a set of entities.
*
* Depending on the configuration of the view mode for each bundle, this can
* be either the display object associated to the view mode, or the 'default'
* display.
*
* This method should only be used internally when rendering an entity. When
* assigning suggested display options for a component in a given view mode,
* entity_get_display() should be used instead, in order to avoid
* inadvertently modifying the output of other view modes that might happen to
* use the 'default' display too. Those options will then be effectively
* applied only if the view mode is configured to use them.
*
* hook_entity_view_display_alter() is invoked on each display, allowing 3rd
* party code to alter the display options held in the display before they are
* used to generate render arrays.
*
* @param \Drupal\Core\Entity\EntityInterface[] $entities
* The entities being rendered. They should all be of the same entity type.
* @param string $view_mode
* The view mode being rendered.
*
* @return \Drupal\Core\Entity\Display\EntityViewDisplayInterface[]
* The display objects to use to render the entities, keyed by entity
* bundle.
*
* @see entity_get_display()
* @see hook_entity_view_display_alter()
*/
public static function collectRenderDisplays($entities, $view_mode) {
if (empty($entities)) {
return array();
}
// Collect entity type and bundles.
$entity_type = current($entities)->getEntityTypeId();
$bundles = array();
foreach ($entities as $entity) {
$bundles[$entity->bundle()] = TRUE;
}
$bundles = array_keys($bundles);
// For each bundle, check the existence and status of:
// - the display for the view mode,
// - the 'default' display.
$candidate_ids = array();
foreach ($bundles as $bundle) {
if ($view_mode != 'default') {
$candidate_ids[$bundle][] = $entity_type . '.' . $bundle . '.' . $view_mode;
}
$candidate_ids[$bundle][] = $entity_type . '.' . $bundle . '.default';
}
$results = \Drupal::entityQuery('entity_view_display')
->condition('id', NestedArray::mergeDeepArray($candidate_ids))
->condition('status', TRUE)
->execute();
// For each bundle, select the first valid candidate display, if any.
$load_ids = array();
foreach ($bundles as $bundle) {
foreach ($candidate_ids[$bundle] as $candidate_id) {
if (isset($results[$candidate_id])) {
$load_ids[$bundle] = $candidate_id;
break;
}
}
}
// Load the selected displays.
$storage = \Drupal::entityManager()->getStorageController('entity_view_display');
$displays = $storage->loadMultiple($load_ids);
$displays_by_bundle = array();
foreach ($bundles as $bundle) {
// Use the selected display if any, or create a fresh runtime object.
if (isset($load_ids[$bundle])) {
$display = $displays[$load_ids[$bundle]];
}
else {
$display = $storage->create(array(
'targetEntityType' => $entity_type,
'bundle' => $bundle,
'mode' => $view_mode,
'status' => TRUE,
));
}
// Let the display know which view mode was originally requested.
$display->originalMode = $view_mode;
// Let modules alter the display.
$display_context = array(
'entity_type' => $entity_type,
'bundle' => $bundle,
'view_mode' => $view_mode,
);
\Drupal::moduleHandler()->alter('entity_view_display', $display, $display_context);
$displays_by_bundle[$bundle] = $display;
}
return $displays_by_bundle;
}
/**
* Returns the display object used to render an entity.
*
* See the collectRenderDisplays() method for details.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity being rendered.
* @param string $view_mode
* The view mode.
*
* @return \Drupal\Core\Entity\Display\EntityViewDisplayInterface
* The display object that should be used to render the entity.
*
* @see \Drupal\entity\Entity\EntityDisplay::collectRenderDisplays()
*/
public static function collectRenderDisplay($entity, $view_mode) {
$displays = static::collectRenderDisplays(array($entity), $view_mode);
return $displays[$entity->bundle()];
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Template\Attribute; use Drupal\Core\Template\Attribute;
use Drupal\entity\Entity\EntityViewDisplay;
/* /*
* Load all public Field API functions. Drupal currently has no * Load all public Field API functions. Drupal currently has no
...@@ -428,7 +429,7 @@ function field_view_field(ContentEntityInterface $entity, $field_name, $display_ ...@@ -428,7 +429,7 @@ function field_view_field(ContentEntityInterface $entity, $field_name, $display_
// Get the formatter object. // Get the formatter object.
if (is_string($display_options)) { if (is_string($display_options)) {
$view_mode = $display_options; $view_mode = $display_options;
$formatter = entity_get_render_display($entity, $view_mode)->getRenderer($field_name); $formatter = EntityViewDisplay::collectRenderDisplay($entity, $view_mode)->getRenderer($field_name);
} }
else { else {
$view_mode = '_custom'; $view_mode = '_custom';
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment