diff --git a/core/modules/layout_builder/src/Form/LayoutBuilderEntityViewDisplayForm.php b/core/modules/layout_builder/src/Form/LayoutBuilderEntityViewDisplayForm.php index 24d8d8ef3e..9f19f71a00 100644 --- a/core/modules/layout_builder/src/Form/LayoutBuilderEntityViewDisplayForm.php +++ b/core/modules/layout_builder/src/Form/LayoutBuilderEntityViewDisplayForm.php @@ -7,6 +7,8 @@ use Drupal\Core\Form\FormStateInterface; use Drupal\field_ui\Form\EntityViewDisplayEditForm; use Drupal\layout_builder\Entity\LayoutEntityDisplayInterface; +use Drupal\layout_builder\LayoutDisplayHelperTrait; +use Drupal\layout_builder\LayoutEntityHelperTrait; use Drupal\layout_builder\Plugin\SectionStorage\OverridesSectionStorage; use Drupal\layout_builder\SectionStorageInterface; @@ -18,6 +20,9 @@ */ class LayoutBuilderEntityViewDisplayForm extends EntityViewDisplayEditForm { + use LayoutDisplayHelperTrait; + use LayoutEntityHelperTrait; + /** * The entity being used by this form. * @@ -106,12 +111,12 @@ public function form(array $form, FormStateInterface $form_state) { // Prevent turning off overrides while any exist. if ($this->hasOverrides($this->entity)) { $form['layout']['enabled']['#disabled'] = TRUE; - $form['layout']['enabled']['#description'] = $this->t('You must revert all customized layouts of this display before you can disable this option.'); + $form['layout']['enabled']['#description'] = $this->t('Because layout overrides are present, this must be done via "Disable Layout Builder for this display and revert all layout overrides"'); $form['layout']['allow_custom']['#disabled'] = TRUE; - $form['layout']['allow_custom']['#description'] = $this->t('You must revert all customized layouts of this display before you can disable this option.'); + $form['layout']['allow_custom']['#description'] = $this->t('Because layout overrides are present, this must be done via "Disable Layout Builder for this display and revert all layout overrides"'); $form['layout']['revert_all'] = [ '#type' => 'submit', - '#value' => $this->t('Disable Layout Builder and Revert all overrides'), + '#value' => $this->t('Disable Layout Builder for this display and revert all layout overrides'), '#button_type' => 'danger', '#submit' => ['::confirmRevertAll'], ]; @@ -168,34 +173,13 @@ protected function isCanonicalMode($mode) { * * @return bool * TRUE if there are any overrides of this default, FALSE otherwise. - * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException - * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException */ protected function hasOverrides(LayoutEntityDisplayInterface $display) { if (!$display->isOverridable()) { return FALSE; } $query = $this->getOverrideQuery($display); - return (bool) $query->count()->execute(); - } - - /** - * Formats the query for checking if this display has overridden entities. - * - * @param \Drupal\layout_builder\Entity\LayoutEntityDisplayInterface $display - * - * @return \Drupal\Core\Entity\Query\QueryInterface - * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException - * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException - */ - protected function getOverrideQuery(LayoutEntityDisplayInterface $display) { - $entity_type = $this->entityTypeManager->getDefinition($display->getTargetEntityTypeId()); - $query = $this->entityTypeManager->getStorage($display->getTargetEntityTypeId())->getQuery() - ->exists(OverridesSectionStorage::FIELD_NAME); - if ($bundle_key = $entity_type->getKey('bundle')) { - $query->condition($bundle_key, $display->getTargetBundle()); - } - return $query; + return (bool) $query->count()->execute(); } /** @@ -256,39 +240,13 @@ protected function buildExtraFieldRow($field_id, $extra_field) { return parent::buildExtraFieldRow($field_id, $extra_field); } - /** - * Reverts the layout on all entities of this type. - * - * @param array $form - * @param \Drupal\Core\Form\FormStateInterface $form_state - * - * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException - * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException - */ - public function revertAll(array &$form, FormStateInterface $form_state) { - $ids = $this->getOverrideQuery($this->entity)->execute(); - $section_storage_manager = \Drupal::service('plugin.manager.layout_builder.section_storage'); - $entity_type_id = $this->entity->getTargetEntityTypeId(); - $layout_tempstore_repository = \Drupal::service('layout_builder.tempstore_repository'); - foreach ($ids as $id) { - /** @var \Drupal\layout_builder\OverridesSectionStorageInterface $section_storage */ - $section_storage = $section_storage_manager->loadFromStorageId('overrides', "$entity_type_id.$id"); - // Remove all sections. - while ($section_storage->count()) { - $section_storage->removeSection(0); - } - $section_storage->save(); - $layout_tempstore_repository->delete($section_storage); - } - $this->messenger()->addStatus($this->t('Layout overrides reverted.')); - } - - /** * Send a user to the confirmation route with route params to get back here. * * @param array $form + * An associative array containing the structure of the form. * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current state of the form. */ public function confirmRevertAll(array &$form, FormStateInterface $form_state) { $form_state->setRedirectUrl($this->sectionStorage->getLayoutBuilderUrl('confirm_revert_all')); diff --git a/core/modules/layout_builder/src/Form/RevertAllConfirm.php b/core/modules/layout_builder/src/Form/RevertAllConfirm.php deleted file mode 100644 index 7730f14365..0000000000 --- a/core/modules/layout_builder/src/Form/RevertAllConfirm.php +++ /dev/null @@ -1,100 +0,0 @@ -get('plugin.manager.layout_builder.section_storage'), - $container->get('layout_builder.tempstore_repository') - ); - } - - /** - * {@inheritdoc} - */ - public function __construct(SectionStorageManager $sectionStorageManager, LayoutTempstoreRepository $layoutTempstoreRepository) { - $this->layoutTempstoreRepository = $sectionStorageManager; - $this->layoutTempstoreRepository = $layoutTempstoreRepository; - } - - /** - * {@inheritdoc} - */ - public function getQuestion() { - return t('Are you sure you want to revert all layouts to the default layout for this display? Layout Builder will also be disabled for this display.'); - } - - /** - * {@inheritdoc} - */ - public function getCancelUrl() { - return $this->sectionStorage->getRedirectUrl(); - } - - /** - * {@inheritdoc} - */ - public function getFormId() { - return 'layout_builder_revert_all'; - } - - /** - * {@inheritdoc} - */ - public function submitForm(array &$form, FormStateInterface $form_state) { - $this->revertAll($form, $form_state); - } - - - /** - * Reverts the layout on all entities of this type. - * - * @param array $form - * @param \Drupal\Core\Form\FormStateInterface $form_state - */ - public function revertAll(array &$form, FormStateInterface $form_state) { - $ids = $this->getOverrideQuery($this->entity)->execute(); - $entity_type_id = $this->entity->getTargetEntityTypeId(); - foreach ($ids as $id) { - /** @var \Drupal\layout_builder\OverridesSectionStorageInterface $section_storage */ - $section_storage = $this->sectionStorageManager->loadFromStorageId('overrides', "$entity_type_id.$id"); - // Remove all sections. - while ($section_storage->count()) { - $section_storage->removeSection(0); - } - $section_storage->save(); - $this->layoutTempstoreRepository->delete($section_storage); - } - $this->messenger()->addStatus($this->t('Layout overrides reverted.')); - } - -} diff --git a/core/modules/layout_builder/src/Form/RevertAllConfirmForm.php b/core/modules/layout_builder/src/Form/RevertAllConfirmForm.php new file mode 100644 index 0000000000..571b23bb4c --- /dev/null +++ b/core/modules/layout_builder/src/Form/RevertAllConfirmForm.php @@ -0,0 +1,142 @@ +get('layout_builder.tempstore_repository'), + $container->get('entity_type.manager') + ); + } + + /** + * {@inheritdoc} + */ + public function __construct(LayoutTempstoreRepository $layout_tempstore_repository, EntityTypeManagerInterface $entity_type_manager, $one = NULL, $two = NULL) { + $this->layoutTempstoreRepository = $layout_tempstore_repository; + $this->entityTypeManager = $entity_type_manager; + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, FormStateInterface $form_state, DefaultsSectionStorageInterface $section_storage = NULL, $more = NULL) { + if (!$section_storage instanceof DefaultsSectionStorageInterface) { + throw new \InvalidArgumentException(sprintf('The section storage with type "%s" and ID "%s" does not provide defaults', $section_storage->getStorageType(), $section_storage->getStorageId())); + } + + $this->sectionStorage = $section_storage; + $this->entity = $this->sectionStorage->getContexts()['display']->getContextValue(); + + // Mark this as an administrative page for JavaScript ("Back to site" link). + $form['#attached']['drupalSettings']['path']['currentPathIsAdmin'] = TRUE; + return parent::buildForm($form, $form_state); + } + + /** + * {@inheritdoc} + */ + public function getQuestion() { + return t('Are you sure you want to revert all layouts to the default layout for this display? Layout Builder will also be disabled for this display.'); + } + + /** + * {@inheritdoc} + */ + public function getCancelUrl() { + return $this->sectionStorage->getRedirectUrl(); + } + + /** + * {@inheritdoc} + */ + public function getFormId() { + return 'layout_builder_revert_all'; + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + $this->revertAll($form, $form_state); + $this->sectionStorage->disableLayoutBuilder()->save(); + $form_state->setRedirectUrl($this->getCancelUrl()); + } + + /** + * Reverts the layout on all entities of this type. + * + * @param array $form + * An associative array containing the structure of the form. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current state of the form. + */ + public function revertAll(array &$form, FormStateInterface $form_state) { + $ids = $this->getOverrideQuery($this->entity)->execute(); + $entity_type_id = $this->entity->getTargetEntityTypeId(); + $entities = $this->entityTypeManager + ->getStorage($entity_type_id) + ->loadMultiple($ids); + /* @var \Drupal\Core\Entity\FieldableEntityInterface $entity_with_override */ + foreach ($entities as $entity_with_override) { + $override_section_storage = $this->getSectionStorageFromEntity($entity_with_override); + $override_section_storage->removeAllSections(); + $override_section_storage->save(); + $this->layoutTempstoreRepository->delete($override_section_storage); + } + + $this->messenger()->addStatus($this->t('Layout overrides reverted.')); + } + +} diff --git a/core/modules/layout_builder/src/LayoutDisplayHelperTrait.php b/core/modules/layout_builder/src/LayoutDisplayHelperTrait.php new file mode 100644 index 0000000000..1bdcdff3ee --- /dev/null +++ b/core/modules/layout_builder/src/LayoutDisplayHelperTrait.php @@ -0,0 +1,38 @@ +entityTypeManager->getDefinition($display->getTargetEntityTypeId()); + $query = $this->entityTypeManager->getStorage($display->getTargetEntityTypeId())->getQuery() + ->exists(OverridesSectionStorage::FIELD_NAME); + if ($bundle_key = $entity_type->getKey('bundle')) { + $query->condition($bundle_key, $display->getTargetBundle()); + } + return $query; + } + +} diff --git a/core/modules/layout_builder/src/LayoutEntityHelperTrait.php b/core/modules/layout_builder/src/LayoutEntityHelperTrait.php index e1c4216ce7..8a0a856a3d 100644 --- a/core/modules/layout_builder/src/LayoutEntityHelperTrait.php +++ b/core/modules/layout_builder/src/LayoutEntityHelperTrait.php @@ -10,6 +10,7 @@ use Drupal\Core\Plugin\Context\Context; use Drupal\Core\Plugin\Context\ContextDefinition; use Drupal\Core\Plugin\Context\EntityContext; +use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay; use Drupal\layout_builder\Entity\LayoutEntityDisplayInterface; use Drupal\layout_builder\Plugin\SectionStorage\OverridesSectionStorage; @@ -177,4 +178,45 @@ private function sectionStorageManager() { return $this->sectionStorageManager ?: \Drupal::service('plugin.manager.layout_builder.section_storage'); } + /** + * Returns the layout override for an entity.. + * + * @param \Drupal\Core\Entity\FieldableEntityInterface $entity + * The entity with the overridden layout. + * + * @return \Drupal\layout_builder\SectionStorageInterface + * The section storage. + */ + public function getSectionStorageFromEntity(FieldableEntityInterface $entity) { + $contexts = $this->getSectionStorageContextFromEntity($entity); + + $contexts['entity'] = EntityContext::fromEntity($entity); + $contexts['view_mode'] = new Context(new ContextDefinition('string'), 'default'); + return $this->sectionStorageManager()->load('overrides', $contexts); + } + + /** + * Returns contexts required to load the layout override for an entity. + * + * @param \Drupal\Core\Entity\FieldableEntityInterface $entity + * The entity. + * + * @return \Drupal\Core\Plugin\Context\ContextInterface[] + * The section storage contexts. + */ + public function getSectionStorageContextFromEntity(FieldableEntityInterface $entity) { + $contexts = []; + + $contexts['entity'] = EntityContext::fromEntity($entity); + // @todo Expand to work for all view modes in + // https://www.drupal.org/node/2907413. + $view_mode = 'full'; + // Retrieve the actual view mode from the returned view display as the + // requested view mode may not exist and a fallback will be used. + $view_mode = LayoutBuilderEntityViewDisplay::collectRenderDisplay($entity, $view_mode)->getMode(); + $contexts['view_mode'] = new Context(new ContextDefinition('string'), $view_mode); + + return $contexts; + } + } diff --git a/core/modules/layout_builder/src/Routing/LayoutBuilderRoutesTrait.php b/core/modules/layout_builder/src/Routing/LayoutBuilderRoutesTrait.php index 19a3b56c80..617ad47487 100644 --- a/core/modules/layout_builder/src/Routing/LayoutBuilderRoutesTrait.php +++ b/core/modules/layout_builder/src/Routing/LayoutBuilderRoutesTrait.php @@ -97,10 +97,14 @@ protected function buildLayoutRoutes(RouteCollection $collection, SectionStorage ->setRequirements($requirements) ->setOptions($disable_options); $collection->add("$route_name_prefix.disable", $route); + + $revert_all_defaults = $disable_defaults; + $revert_all_defaults['_form'] = '\Drupal\layout_builder\Form\RevertAllConfirmForm'; + $revert_all_options = $disable_options; $revertAllRoute = (new Route("$path/revert-all")) - ->setDefaults($disable_defaults) + ->setDefaults($revert_all_defaults) ->setRequirements($requirements) - ->setOptions($disable_options); + ->setOptions($revert_all_options); $collection->add("$route_name_prefix.confirm_revert_all", $revertAllRoute); } } diff --git a/core/modules/layout_builder/tests/src/Unit/DefaultsSectionStorageTest.php b/core/modules/layout_builder/tests/src/Unit/DefaultsSectionStorageTest.php index f36b8fbc94..605cb8e864 100644 --- a/core/modules/layout_builder/tests/src/Unit/DefaultsSectionStorageTest.php +++ b/core/modules/layout_builder/tests/src/Unit/DefaultsSectionStorageTest.php @@ -448,6 +448,25 @@ public function testBuildRoutes() { ], ] ), + 'layout_builder.defaults.with_bundle_key.confirm_revert_all' => new Route( + '/admin/entity/whatever/display/{view_mode_name}/layout/revert-all', + [ + 'entity_type_id' => 'with_bundle_key', + 'bundle_key' => 'my_bundle_type', + 'section_storage_type' => 'defaults', + 'section_storage' => '', + '_form' => '\Drupal\layout_builder\Form\RevertAllConfirmForm', + ], + [ + '_field_ui_view_mode_access' => 'administer with_bundle_key display', + '_layout_builder_access' => 'view', + ], + [ + 'parameters' => [ + 'section_storage' => ['layout_builder_tempstore' => TRUE], + ], + ] + ), 'layout_builder.defaults.with_bundle_parameter.view' => new Route( '/admin/entity/{bundle}/display/{view_mode_name}/layout', [ @@ -507,6 +526,24 @@ public function testBuildRoutes() { ], ] ), + 'layout_builder.defaults.with_bundle_parameter.confirm_revert_all' => new Route( + '/admin/entity/{bundle}/display/{view_mode_name}/layout/revert-all', + [ + 'entity_type_id' => 'with_bundle_parameter', + 'section_storage_type' => 'defaults', + 'section_storage' => '', + '_form' => '\Drupal\layout_builder\Form\RevertAllConfirmForm', + ], + [ + '_field_ui_view_mode_access' => 'administer with_bundle_parameter display', + '_layout_builder_access' => 'view', + ], + [ + 'parameters' => [ + 'section_storage' => ['layout_builder_tempstore' => TRUE], + ], + ] + ), ]; $collection = new RouteCollection();