diff --git a/core/includes/entity.inc b/core/includes/entity.inc index 116b786..eb108ff 100644 --- a/core/includes/entity.inc +++ b/core/includes/entity.inc @@ -651,58 +651,6 @@ function entity_get_form_display($entity_type, $bundle, $form_mode) { } /** - * Returns the entity_form_display object 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 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. * * @param \Drupal\Core\Entity\EntityInterface $entity diff --git a/core/lib/Drupal/Core/Entity/EntityFormController.php b/core/lib/Drupal/Core/Entity/EntityFormController.php index 342d395..440aa50 100644 --- a/core/lib/Drupal/Core/Entity/EntityFormController.php +++ b/core/lib/Drupal/Core/Entity/EntityFormController.php @@ -10,6 +10,7 @@ use Drupal\Core\Entity\Display\EntityFormDisplayInterface; use Drupal\Core\Form\FormBase; use Drupal\Core\Extension\ModuleHandlerInterface; +use Drupal\entity\Entity\EntityFormDisplay; /** * Base class for entity form controllers. @@ -121,7 +122,7 @@ protected function init(array &$form_state) { // Prepare the entity to be presented in the entity form. $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); // Invoke the prepare form hooks. diff --git a/core/modules/edit/lib/Drupal/edit/Form/EditFieldForm.php b/core/modules/edit/lib/Drupal/edit/Form/EditFieldForm.php index f6f5a94..e930206 100644 --- a/core/modules/edit/lib/Drupal/edit/Form/EditFieldForm.php +++ b/core/modules/edit/lib/Drupal/edit/Form/EditFieldForm.php @@ -7,13 +7,14 @@ namespace Drupal\edit\Form; -use Drupal\Core\Form\FormBase; -use Symfony\Component\DependencyInjection\ContainerInterface; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityStorageControllerInterface; +use Drupal\Core\Entity\EntityChangedInterface; use Drupal\Core\Extension\ModuleHandlerInterface; +use Drupal\Core\Form\FormBase; +use Drupal\entity\Entity\EntityFormDisplay; 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. @@ -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 // UI for them. - $form_state['form_display'] = entity_get_render_form_display($entity, 'default'); + $form_state['form_display'] = EntityFormDisplay::collectRenderDisplay($entity, 'default'); } /** diff --git a/core/modules/entity/lib/Drupal/entity/Entity/EntityDisplay.php b/core/modules/entity/lib/Drupal/entity/Entity/EntityDisplay.php index b937827..d2da537 100644 --- a/core/modules/entity/lib/Drupal/entity/Entity/EntityDisplay.php +++ b/core/modules/entity/lib/Drupal/entity/Entity/EntityDisplay.php @@ -7,6 +7,7 @@ namespace Drupal\entity\Entity; +use Drupal\Component\Utility\NestedArray; use Drupal\Core\Entity\Display\EntityViewDisplayInterface; use Drupal\entity\EntityDisplayBase; @@ -42,13 +43,17 @@ class EntityDisplay extends EntityDisplayBase implements EntityViewDisplayInterf * 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 + * 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_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 @@ -57,6 +62,9 @@ class EntityDisplay extends EntityDisplayBase implements EntityViewDisplayInterf * @return \Drupal\Core\Entity\Display\EntityViewDisplayInterface[] * The display objects that should be used to render the entities, keyed by * entity bundle. + * + * @see entity_get_display() + * @see hook_entity_display_alter() */ public static function collectRenderDisplays($entities, $view_mode) { if (empty($entities)) { @@ -71,41 +79,35 @@ public static function collectRenderDisplays($entities, $view_mode) { } $bundles = array_keys($bundles); - // For each bundle, check the existence and status of the 'default' display - // and the display for the view mode. + // 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) { - $candidate_ids["$bundle:default"] = $entity_type . '.' . $bundle . '.default'; if ($view_mode != 'default') { - $candidate_ids["$bundle:$view_mode"] = $entity_type . '.' . $bundle . '.' . $view_mode; + $candidate_ids[$bundle][] = $entity_type . '.' . $bundle . '.' . $view_mode; } + $candidate_ids[$bundle][] = $entity_type . '.' . $bundle . '.default'; } $results = \Drupal::entityQuery('entity_display') - ->condition('id', $candidate_ids) + ->condition('id', NestedArray::mergeDeepArray($candidate_ids)) ->condition('status', TRUE) ->execute(); - // Determine the actual display to load for each bundle. + // For each bundle, select the first valid candidate display, if any. $load_ids = array(); foreach ($bundles as $bundle) { - // Use the display for the view mode if it exists. - if ($view_mode != 'default') { - $candidate_id = $candidate_ids["$bundle:$view_mode"]; - if (isset($results[$candidate_id])) { - $load_ids[$bundle] = $candidate_id; - } - } - // Else, use the 'default' display if it exists. - if (empty($load_ids[$bundle])) { - $candidate_id = $candidate_ids["$bundle:default"]; + foreach ($candidate_ids[$bundle] as $candidate_id) { if (isset($results[$candidate_id])) { $load_ids[$bundle] = $candidate_id; + break; } } } // Load the selected displays. - $displays = \Drupal::entityManager()->getStorageController('entity_display')->loadMultiple($load_ids); + $storage = \Drupal::entityManager()->getStorageController('entity_display'); + $displays = $storage->loadMultiple($load_ids); $displays_by_bundle = array(); foreach ($bundles as $bundle) { @@ -114,7 +116,12 @@ public static function collectRenderDisplays($entities, $view_mode) { $display = $displays[$load_ids[$bundle]]; } else { - $display = entity_get_display($entity_type, $bundle, 'default'); + $display = $storage->create(array( + 'targetEntityType' => $entity_type, + 'bundle' => $bundle, + 'mode' => $view_mode, + 'status' => TRUE, + )); } // Let the display know which view mode was originally requested. diff --git a/core/modules/entity/lib/Drupal/entity/Entity/EntityFormDisplay.php b/core/modules/entity/lib/Drupal/entity/Entity/EntityFormDisplay.php index ec22794..851f25c 100644 --- a/core/modules/entity/lib/Drupal/entity/Entity/EntityFormDisplay.php +++ b/core/modules/entity/lib/Drupal/entity/Entity/EntityFormDisplay.php @@ -36,6 +36,83 @@ class EntityFormDisplay extends EntityDisplayBase implements EntityFormDisplayIn protected $displayContext = 'form'; /** + * Returns the entity_form_display object used to render 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[] $entities + * The entities being rendered. They should all be of the same entity type. + * @param string $form_mode + * The form mode being rendered. + * + * @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} */ public function __construct(array $values, $entity_type) {