Issue #2936358 by tim.plunkett, johndevman, tedbow, eiriksm, AaronMcHale, phenaproxima, pookmish, alexpott: Layout Builder should be opt-in per display (entity type/bundle/view mode)
parent
df94b0c1ef
commit
c6cdc43923
|
@ -2,6 +2,9 @@ core.entity_view_display.*.*.*.third_party.layout_builder:
|
|||
type: mapping
|
||||
label: 'Per-view-mode Layout Builder settings'
|
||||
mapping:
|
||||
enabled:
|
||||
type: boolean
|
||||
label: 'Whether the Layout Builder is enabled for this display'
|
||||
allow_custom:
|
||||
type: boolean
|
||||
label: 'Allow a customized layout'
|
||||
|
|
|
@ -13,6 +13,8 @@ use Drupal\layout_builder\Section;
|
|||
* Implements hook_install().
|
||||
*/
|
||||
function layout_builder_install() {
|
||||
$display_changed = FALSE;
|
||||
|
||||
$displays = LayoutBuilderEntityViewDisplay::loadMultiple();
|
||||
/** @var \Drupal\layout_builder\Entity\LayoutEntityDisplayInterface[] $displays */
|
||||
foreach ($displays as $display) {
|
||||
|
@ -20,21 +22,43 @@ function layout_builder_install() {
|
|||
$field_layout = $display->getThirdPartySettings('field_layout');
|
||||
if (isset($field_layout['id'])) {
|
||||
$field_layout += ['settings' => []];
|
||||
$display->appendSection(new Section($field_layout['id'], $field_layout['settings']));
|
||||
$display
|
||||
->enableLayoutBuilder()
|
||||
->appendSection(new Section($field_layout['id'], $field_layout['settings']))
|
||||
->save();
|
||||
$display_changed = TRUE;
|
||||
}
|
||||
|
||||
// Sort the components by weight.
|
||||
$components = $display->get('content');
|
||||
uasort($components, 'Drupal\Component\Utility\SortArray::sortByWeightElement');
|
||||
foreach ($components as $name => $component) {
|
||||
$display->setComponent($name, $component);
|
||||
}
|
||||
$display->save();
|
||||
}
|
||||
|
||||
// Clear the rendered cache to ensure the new layout builder flow is used.
|
||||
// While in many cases the above change will not affect the rendered output,
|
||||
// the cacheability metadata will have changed and should be processed to
|
||||
// prepare for future changes.
|
||||
Cache::invalidateTags(['rendered']);
|
||||
if ($display_changed) {
|
||||
Cache::invalidateTags(['rendered']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable Layout Builder for existing entity displays.
|
||||
*/
|
||||
function layout_builder_update_8601(&$sandbox) {
|
||||
$config_factory = \Drupal::configFactory();
|
||||
|
||||
if (!isset($sandbox['count'])) {
|
||||
$sandbox['ids'] = $config_factory->listAll('core.entity_view_display.');
|
||||
$sandbox['count'] = count($sandbox['ids']);
|
||||
}
|
||||
|
||||
$ids = array_splice($sandbox['ids'], 0, 50);
|
||||
foreach ($ids as $id) {
|
||||
$display = $config_factory->getEditable($id);
|
||||
if ($display->get('third_party_settings.layout_builder')) {
|
||||
$display
|
||||
->set('third_party_settings.layout_builder.enabled', TRUE)
|
||||
->save();
|
||||
}
|
||||
}
|
||||
|
||||
$sandbox['#finished'] = empty($sandbox['ids']) ? 1 : ($sandbox['count'] - count($sandbox['ids'])) / $sandbox['count'];
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
use Drupal\Core\Config\Entity\ConfigEntityUpdater;
|
||||
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
|
||||
use Drupal\layout_builder\Entity\LayoutEntityDisplayInterface;
|
||||
|
||||
/**
|
||||
* Rebuild plugin dependencies for all entity view displays.
|
||||
|
@ -39,7 +39,11 @@ function layout_builder_post_update_rebuild_plugin_dependencies(&$sandbox = NULL
|
|||
*/
|
||||
function layout_builder_post_update_add_extra_fields(&$sandbox = NULL) {
|
||||
$entity_field_manager = \Drupal::service('entity_field.manager');
|
||||
\Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'entity_view_display', function (EntityViewDisplayInterface $display) use ($entity_field_manager) {
|
||||
\Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'entity_view_display', function (LayoutEntityDisplayInterface $display) use ($entity_field_manager) {
|
||||
if (!$display->isLayoutBuilderEnabled()) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$extra_fields = $entity_field_manager->getExtraFields($display->getTargetEntityTypeId(), $display->getTargetBundle());
|
||||
$components = $display->getComponents();
|
||||
// Sort the components to avoid them being reordered by setComponent().
|
||||
|
|
|
@ -4,6 +4,7 @@ layout_builder.choose_section:
|
|||
_controller: '\Drupal\layout_builder\Controller\ChooseSectionController::build'
|
||||
requirements:
|
||||
_permission: 'configure any layout'
|
||||
_layout_builder_access: 'view'
|
||||
options:
|
||||
_admin_route: TRUE
|
||||
parameters:
|
||||
|
@ -16,6 +17,7 @@ layout_builder.add_section:
|
|||
_controller: '\Drupal\layout_builder\Controller\AddSectionController::build'
|
||||
requirements:
|
||||
_permission: 'configure any layout'
|
||||
_layout_builder_access: 'view'
|
||||
options:
|
||||
_admin_route: TRUE
|
||||
parameters:
|
||||
|
@ -32,6 +34,7 @@ layout_builder.configure_section:
|
|||
plugin_id: null
|
||||
requirements:
|
||||
_permission: 'configure any layout'
|
||||
_layout_builder_access: 'view'
|
||||
options:
|
||||
_admin_route: TRUE
|
||||
parameters:
|
||||
|
@ -44,6 +47,7 @@ layout_builder.remove_section:
|
|||
_form: '\Drupal\layout_builder\Form\RemoveSectionForm'
|
||||
requirements:
|
||||
_permission: 'configure any layout'
|
||||
_layout_builder_access: 'view'
|
||||
options:
|
||||
_admin_route: TRUE
|
||||
parameters:
|
||||
|
@ -56,6 +60,7 @@ layout_builder.choose_block:
|
|||
_controller: '\Drupal\layout_builder\Controller\ChooseBlockController::build'
|
||||
requirements:
|
||||
_permission: 'configure any layout'
|
||||
_layout_builder_access: 'view'
|
||||
options:
|
||||
_admin_route: TRUE
|
||||
parameters:
|
||||
|
@ -68,6 +73,7 @@ layout_builder.add_block:
|
|||
_form: '\Drupal\layout_builder\Form\AddBlockForm'
|
||||
requirements:
|
||||
_permission: 'configure any layout'
|
||||
_layout_builder_access: 'view'
|
||||
options:
|
||||
_admin_route: TRUE
|
||||
parameters:
|
||||
|
@ -80,6 +86,7 @@ layout_builder.update_block:
|
|||
_form: '\Drupal\layout_builder\Form\UpdateBlockForm'
|
||||
requirements:
|
||||
_permission: 'configure any layout'
|
||||
_layout_builder_access: 'view'
|
||||
options:
|
||||
_admin_route: TRUE
|
||||
parameters:
|
||||
|
@ -92,6 +99,7 @@ layout_builder.remove_block:
|
|||
_form: '\Drupal\layout_builder\Form\RemoveBlockForm'
|
||||
requirements:
|
||||
_permission: 'configure any layout'
|
||||
_layout_builder_access: 'view'
|
||||
options:
|
||||
_admin_route: TRUE
|
||||
parameters:
|
||||
|
@ -110,6 +118,7 @@ layout_builder.move_block:
|
|||
preceding_block_uuid: null
|
||||
requirements:
|
||||
_permission: 'configure any layout'
|
||||
_layout_builder_access: 'view'
|
||||
options:
|
||||
_admin_route: TRUE
|
||||
parameters:
|
||||
|
|
|
@ -2,6 +2,10 @@ services:
|
|||
layout_builder.tempstore_repository:
|
||||
class: Drupal\layout_builder\LayoutTempstoreRepository
|
||||
arguments: ['@tempstore.shared']
|
||||
access_check.entity.layout_builder_access:
|
||||
class: Drupal\layout_builder\Access\LayoutBuilderAccessCheck
|
||||
tags:
|
||||
- { name: access_check, applies_to: _layout_builder_access }
|
||||
access_check.entity.layout:
|
||||
class: Drupal\layout_builder\Access\LayoutSectionAccessCheck
|
||||
tags:
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\layout_builder\Access;
|
||||
|
||||
use Drupal\Core\Cache\RefinableCacheableDependencyInterface;
|
||||
use Drupal\Core\Routing\Access\AccessInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\layout_builder\SectionStorageInterface;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
/**
|
||||
* Provides an access check for the Layout Builder defaults.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class LayoutBuilderAccessCheck implements AccessInterface {
|
||||
|
||||
/**
|
||||
* Checks routing access to the layout.
|
||||
*
|
||||
* @param \Drupal\layout_builder\SectionStorageInterface $section_storage
|
||||
* The section storage.
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* The current user.
|
||||
* @param \Symfony\Component\Routing\Route $route
|
||||
* The route to check against.
|
||||
*
|
||||
* @return \Drupal\Core\Access\AccessResultInterface
|
||||
* The access result.
|
||||
*/
|
||||
public function access(SectionStorageInterface $section_storage, AccountInterface $account, Route $route) {
|
||||
$operation = $route->getRequirement('_layout_builder_access');
|
||||
$access = $section_storage->access($operation, $account, TRUE);
|
||||
if ($access instanceof RefinableCacheableDependencyInterface) {
|
||||
$access->addCacheableDependency($section_storage);
|
||||
}
|
||||
return $access;
|
||||
}
|
||||
|
||||
}
|
|
@ -11,8 +11,10 @@ use Drupal\Core\Config\Entity\ThirdPartySettingsInterface;
|
|||
* Layout Builder is currently experimental and should only be leveraged by
|
||||
* experimental modules and development releases of contributed modules.
|
||||
* See https://www.drupal.org/core/experimental for more information.
|
||||
*
|
||||
* @todo Refactor this interface in https://www.drupal.org/node/2985362.
|
||||
*/
|
||||
interface DefaultsSectionStorageInterface extends SectionStorageInterface, ThirdPartySettingsInterface {
|
||||
interface DefaultsSectionStorageInterface extends SectionStorageInterface, ThirdPartySettingsInterface, LayoutBuilderEnabledInterface {
|
||||
|
||||
/**
|
||||
* Determines if the defaults allow custom overrides.
|
||||
|
|
|
@ -58,6 +58,30 @@ class LayoutBuilderEntityViewDisplay extends BaseEntityViewDisplay implements La
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isLayoutBuilderEnabled() {
|
||||
return (bool) $this->getThirdPartySetting('layout_builder', 'enabled');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function enableLayoutBuilder() {
|
||||
$this->setThirdPartySetting('layout_builder', 'enabled', TRUE);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function disableLayoutBuilder() {
|
||||
$this->setOverridable(FALSE);
|
||||
$this->setThirdPartySetting('layout_builder', 'enabled', FALSE);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -92,6 +116,27 @@ class LayoutBuilderEntityViewDisplay extends BaseEntityViewDisplay implements La
|
|||
$field->delete();
|
||||
}
|
||||
}
|
||||
|
||||
$already_enabled = isset($this->original) ? $this->original->isLayoutBuilderEnabled() : FALSE;
|
||||
$set_enabled = $this->isLayoutBuilderEnabled();
|
||||
if ($already_enabled !== $set_enabled) {
|
||||
if ($set_enabled) {
|
||||
// Loop through all existing field-based components and add them as
|
||||
// section-based components.
|
||||
$components = $this->getComponents();
|
||||
// Sort the components by weight.
|
||||
uasort($components, 'Drupal\Component\Utility\SortArray::sortByWeightElement');
|
||||
foreach ($components as $name => $component) {
|
||||
$this->setComponent($name, $component);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// When being disabled, remove all existing section data.
|
||||
while (count($this) > 0) {
|
||||
$this->removeSection(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -153,6 +198,9 @@ class LayoutBuilderEntityViewDisplay extends BaseEntityViewDisplay implements La
|
|||
*/
|
||||
public function buildMultiple(array $entities) {
|
||||
$build_list = parent::buildMultiple($entities);
|
||||
if (!$this->isLayoutBuilderEnabled()) {
|
||||
return $build_list;
|
||||
}
|
||||
|
||||
/** @var \Drupal\Core\Entity\EntityInterface $entity */
|
||||
foreach ($entities as $id => $entity) {
|
||||
|
@ -272,6 +320,11 @@ class LayoutBuilderEntityViewDisplay extends BaseEntityViewDisplay implements La
|
|||
return $this;
|
||||
}
|
||||
|
||||
// Only continue if Layout Builder is enabled.
|
||||
if (!$this->isLayoutBuilderEnabled()) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
// Retrieve the updated options after the parent:: call.
|
||||
$options = $this->content[$name];
|
||||
// Provide backwards compatibility by converting to a section component.
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace Drupal\layout_builder\Entity;
|
||||
|
||||
use Drupal\Core\Entity\Display\EntityDisplayInterface;
|
||||
use Drupal\layout_builder\LayoutBuilderEnabledInterface;
|
||||
use Drupal\layout_builder\SectionListInterface;
|
||||
|
||||
/**
|
||||
|
@ -12,8 +13,10 @@ use Drupal\layout_builder\SectionListInterface;
|
|||
* Layout Builder is currently experimental and should only be leveraged by
|
||||
* experimental modules and development releases of contributed modules.
|
||||
* See https://www.drupal.org/core/experimental for more information.
|
||||
*
|
||||
* @todo Refactor this interface in https://www.drupal.org/node/2985362.
|
||||
*/
|
||||
interface LayoutEntityDisplayInterface extends EntityDisplayInterface, SectionListInterface {
|
||||
interface LayoutEntityDisplayInterface extends EntityDisplayInterface, SectionListInterface, LayoutBuilderEnabledInterface {
|
||||
|
||||
/**
|
||||
* Determines if the display allows custom overrides.
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\layout_builder\Form;
|
||||
|
||||
use Drupal\Core\Form\ConfirmFormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Messenger\MessengerInterface;
|
||||
use Drupal\layout_builder\DefaultsSectionStorageInterface;
|
||||
use Drupal\layout_builder\LayoutTempstoreRepositoryInterface;
|
||||
use Drupal\layout_builder\SectionStorageInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Disables Layout Builder for a given default.
|
||||
*/
|
||||
class LayoutBuilderDisableForm extends ConfirmFormBase {
|
||||
|
||||
/**
|
||||
* The layout tempstore repository.
|
||||
*
|
||||
* @var \Drupal\layout_builder\LayoutTempstoreRepositoryInterface
|
||||
*/
|
||||
protected $layoutTempstoreRepository;
|
||||
|
||||
/**
|
||||
* The section storage.
|
||||
*
|
||||
* @var \Drupal\layout_builder\DefaultsSectionStorageInterface
|
||||
*/
|
||||
protected $sectionStorage;
|
||||
|
||||
/**
|
||||
* Constructs a new RevertOverridesForm.
|
||||
*
|
||||
* @param \Drupal\layout_builder\LayoutTempstoreRepositoryInterface $layout_tempstore_repository
|
||||
* The layout tempstore repository.
|
||||
* @param \Drupal\Core\Messenger\MessengerInterface $messenger
|
||||
* The messenger service.
|
||||
*/
|
||||
public function __construct(LayoutTempstoreRepositoryInterface $layout_tempstore_repository, MessengerInterface $messenger) {
|
||||
$this->layoutTempstoreRepository = $layout_tempstore_repository;
|
||||
$this->setMessenger($messenger);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('layout_builder.tempstore_repository'),
|
||||
$container->get('messenger')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'layout_builder_disable_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getQuestion() {
|
||||
return $this->t('Are you sure you want to disable Layout Builder?');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDescription() {
|
||||
return $this->t('All customizations will be removed. This action cannot be undone.');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCancelUrl() {
|
||||
return $this->sectionStorage->getRedirectUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, SectionStorageInterface $section_storage = 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;
|
||||
return parent::buildForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$this->sectionStorage->disableLayoutBuilder()->save();
|
||||
$this->layoutTempstoreRepository->delete($this->sectionStorage);
|
||||
|
||||
$this->messenger()->addMessage($this->t('Layout Builder has been disabled.'));
|
||||
$form_state->setRedirectUrl($this->getCancelUrl());
|
||||
}
|
||||
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Drupal\layout_builder\Form;
|
||||
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Field\FieldDefinitionInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\field_ui\Form\EntityViewDisplayEditForm;
|
||||
|
@ -28,7 +29,7 @@ class LayoutBuilderEntityViewDisplayForm extends EntityViewDisplayEditForm {
|
|||
/**
|
||||
* The storage section.
|
||||
*
|
||||
* @var \Drupal\layout_builder\SectionStorageInterface
|
||||
* @var \Drupal\layout_builder\DefaultsSectionStorageInterface
|
||||
*/
|
||||
protected $sectionStorage;
|
||||
|
||||
|
@ -46,10 +47,17 @@ class LayoutBuilderEntityViewDisplayForm extends EntityViewDisplayEditForm {
|
|||
public function form(array $form, FormStateInterface $form_state) {
|
||||
$form = parent::form($form, $form_state);
|
||||
|
||||
// Hide the table of fields.
|
||||
$form['fields']['#access'] = FALSE;
|
||||
$form['#fields'] = [];
|
||||
$form['#extra'] = [];
|
||||
$is_enabled = $this->entity->isLayoutBuilderEnabled();
|
||||
if ($is_enabled) {
|
||||
// Hide the table of fields.
|
||||
$form['fields']['#access'] = FALSE;
|
||||
$form['#fields'] = [];
|
||||
$form['#extra'] = [];
|
||||
}
|
||||
else {
|
||||
// Remove the Layout Builder field from the list.
|
||||
$form['#fields'] = array_diff($form['#fields'], ['layout_builder__layout']);
|
||||
}
|
||||
|
||||
$form['manage_layout'] = [
|
||||
'#type' => 'link',
|
||||
|
@ -57,18 +65,26 @@ class LayoutBuilderEntityViewDisplayForm extends EntityViewDisplayEditForm {
|
|||
'#weight' => -10,
|
||||
'#attributes' => ['class' => ['button']],
|
||||
'#url' => $this->sectionStorage->getLayoutBuilderUrl(),
|
||||
'#access' => $is_enabled,
|
||||
];
|
||||
|
||||
$form['layout'] = [
|
||||
'#type' => 'details',
|
||||
'#open' => TRUE,
|
||||
'#title' => $this->t('Layout options'),
|
||||
'#tree' => TRUE,
|
||||
];
|
||||
|
||||
$form['layout']['enabled'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Use Layout Builder'),
|
||||
'#default_value' => $is_enabled,
|
||||
];
|
||||
$form['#entity_builders']['layout_builder'] = '::entityFormEntityBuild';
|
||||
|
||||
// @todo Expand to work for all view modes in
|
||||
// https://www.drupal.org/node/2907413.
|
||||
if ($this->entity->getMode() === 'default') {
|
||||
$form['layout'] = [
|
||||
'#type' => 'details',
|
||||
'#open' => TRUE,
|
||||
'#title' => $this->t('Layout options'),
|
||||
'#tree' => TRUE,
|
||||
];
|
||||
|
||||
$entity_type = $this->entityTypeManager->getDefinition($this->entity->getTargetEntityTypeId());
|
||||
$form['layout']['allow_custom'] = [
|
||||
'#type' => 'checkbox',
|
||||
|
@ -76,14 +92,26 @@ class LayoutBuilderEntityViewDisplayForm extends EntityViewDisplayEditForm {
|
|||
'@entity' => $entity_type->getSingularLabel(),
|
||||
]),
|
||||
'#default_value' => $this->entity->isOverridable(),
|
||||
'#states' => [
|
||||
'disabled' => [
|
||||
':input[name="layout[enabled]"]' => ['checked' => FALSE],
|
||||
],
|
||||
'invisible' => [
|
||||
':input[name="layout[enabled]"]' => ['checked' => FALSE],
|
||||
],
|
||||
],
|
||||
];
|
||||
if (!$is_enabled) {
|
||||
$form['layout']['allow_custom']['#attributes']['disabled'] = 'disabled';
|
||||
}
|
||||
// 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']['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.');
|
||||
}
|
||||
else {
|
||||
$form['#entity_builders'][] = '::entityFormEntityBuild';
|
||||
unset($form['layout']['allow_custom']['#states']);
|
||||
unset($form['#entity_builders']['layout_builder']);
|
||||
}
|
||||
}
|
||||
return $form;
|
||||
|
@ -112,26 +140,62 @@ class LayoutBuilderEntityViewDisplayForm extends EntityViewDisplayEditForm {
|
|||
return (bool) $query->count()->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function copyFormValuesToEntity(EntityInterface $entity, array $form, FormStateInterface $form_state) {
|
||||
// Do not process field values if Layout Builder is or will be enabled.
|
||||
$set_enabled = (bool) $form_state->getValue(['layout', 'enabled'], FALSE);
|
||||
/** @var \Drupal\layout_builder\Entity\LayoutEntityDisplayInterface $entity */
|
||||
$already_enabled = $entity->isLayoutBuilderEnabled();
|
||||
if ($already_enabled || $set_enabled) {
|
||||
$form['#fields'] = [];
|
||||
$form['#extra'] = [];
|
||||
}
|
||||
|
||||
parent::copyFormValuesToEntity($entity, $form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Entity builder for layout options on the entity view display form.
|
||||
*/
|
||||
public function entityFormEntityBuild($entity_type_id, LayoutEntityDisplayInterface $display, &$form, FormStateInterface &$form_state) {
|
||||
$new_value = (bool) $form_state->getValue(['layout', 'allow_custom'], FALSE);
|
||||
$display->setOverridable($new_value);
|
||||
$set_enabled = (bool) $form_state->getValue(['layout', 'enabled'], FALSE);
|
||||
$already_enabled = $display->isLayoutBuilderEnabled();
|
||||
|
||||
if ($set_enabled) {
|
||||
$overridable = (bool) $form_state->getValue(['layout', 'allow_custom'], FALSE);
|
||||
$display->setOverridable($overridable);
|
||||
|
||||
if (!$already_enabled) {
|
||||
$display->enableLayoutBuilder();
|
||||
}
|
||||
}
|
||||
elseif ($already_enabled) {
|
||||
$form_state->setRedirectUrl($this->sectionStorage->getLayoutBuilderUrl('disable'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function buildFieldRow(FieldDefinitionInterface $field_definition, array $form, FormStateInterface $form_state) {
|
||||
// Intentionally empty.
|
||||
if ($this->entity->isLayoutBuilderEnabled() || $field_definition->getType() === 'layout_section') {
|
||||
return [];
|
||||
}
|
||||
|
||||
return parent::buildFieldRow($field_definition, $form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function buildExtraFieldRow($field_id, $extra_field) {
|
||||
// Intentionally empty.
|
||||
if ($this->entity->isLayoutBuilderEnabled()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return parent::buildExtraFieldRow($field_id, $extra_field);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\layout_builder;
|
||||
|
||||
/**
|
||||
* Provides methods for enabling and disabling Layout Builder.
|
||||
*/
|
||||
interface LayoutBuilderEnabledInterface {
|
||||
|
||||
/**
|
||||
* Determines if Layout Builder is enabled.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if Layout Builder is enabled, FALSE otherwise.
|
||||
*/
|
||||
public function isLayoutBuilderEnabled();
|
||||
|
||||
/**
|
||||
* Enables the Layout Builder.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function enableLayoutBuilder();
|
||||
|
||||
/**
|
||||
* Disables the Layout Builder.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function disableLayoutBuilder();
|
||||
|
||||
}
|
|
@ -3,12 +3,14 @@
|
|||
namespace Drupal\layout_builder\Plugin\SectionStorage;
|
||||
|
||||
use Drupal\Component\Utility\NestedArray;
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Entity\FieldableEntityInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Core\Plugin\Context\EntityContext;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\field_ui\FieldUI;
|
||||
use Drupal\layout_builder\DefaultsSectionStorageInterface;
|
||||
|
@ -123,8 +125,8 @@ class DefaultsSectionStorage extends SectionStorageBase implements ContainerFact
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getLayoutBuilderUrl() {
|
||||
return Url::fromRoute("layout_builder.{$this->getStorageType()}.{$this->getDisplay()->getTargetEntityTypeId()}.view", $this->getRouteParameters());
|
||||
public function getLayoutBuilderUrl($rel = 'view') {
|
||||
return Url::fromRoute("layout_builder.{$this->getStorageType()}.{$this->getDisplay()->getTargetEntityTypeId()}.$rel", $this->getRouteParameters());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -296,6 +298,29 @@ class DefaultsSectionStorage extends SectionStorageBase implements ContainerFact
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isLayoutBuilderEnabled() {
|
||||
return $this->getDisplay()->isLayoutBuilderEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function enableLayoutBuilder() {
|
||||
$this->getDisplay()->enableLayoutBuilder();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function disableLayoutBuilder() {
|
||||
$this->getDisplay()->disableLayoutBuilder();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -325,4 +350,12 @@ class DefaultsSectionStorage extends SectionStorageBase implements ContainerFact
|
|||
return $this->getDisplay()->getThirdPartyProviders();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function access($operation, AccountInterface $account = NULL, $return_as_object = FALSE) {
|
||||
$result = AccessResult::allowedIf($this->isLayoutBuilderEnabled());
|
||||
return $return_as_object ? $result : $result->isAllowed();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Drupal\layout_builder\Plugin\SectionStorage;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Entity\EntityFieldManagerInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
|
@ -9,6 +10,7 @@ use Drupal\Core\Entity\FieldableEntityInterface;
|
|||
use Drupal\Core\Field\FieldItemListInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Core\Plugin\Context\EntityContext;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay;
|
||||
use Drupal\layout_builder\OverridesSectionStorageInterface;
|
||||
|
@ -200,10 +202,10 @@ class OverridesSectionStorage extends SectionStorageBase implements ContainerFac
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getLayoutBuilderUrl() {
|
||||
public function getLayoutBuilderUrl($rel = 'view') {
|
||||
$entity = $this->getEntity();
|
||||
$route_parameters[$entity->getEntityTypeId()] = $entity->id();
|
||||
return Url::fromRoute("layout_builder.{$this->getStorageType()}.{$this->getEntity()->getEntityTypeId()}.view", $route_parameters);
|
||||
return Url::fromRoute("layout_builder.{$this->getStorageType()}.{$this->getEntity()->getEntityTypeId()}.$rel", $route_parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -229,4 +231,13 @@ class OverridesSectionStorage extends SectionStorageBase implements ContainerFac
|
|||
return $this->getEntity()->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function access($operation, AccountInterface $account = NULL, $return_as_object = FALSE) {
|
||||
$default_section_storage = $this->getDefaultSectionStorage();
|
||||
$result = AccessResult::allowedIf($default_section_storage->isLayoutBuilderEnabled())->addCacheableDependency($default_section_storage);
|
||||
return $return_as_object ? $result : $result->isAllowed();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace Drupal\layout_builder\Routing;
|
||||
|
||||
use Drupal\Component\Utility\NestedArray;
|
||||
use Drupal\layout_builder\DefaultsSectionStorageInterface;
|
||||
use Drupal\layout_builder\OverridesSectionStorageInterface;
|
||||
use Drupal\layout_builder\SectionStorage\SectionStorageDefinition;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
@ -43,6 +44,7 @@ trait LayoutBuilderRoutesTrait {
|
|||
$defaults['section_storage'] = '';
|
||||
// Trigger the layout builder access check.
|
||||
$requirements['_has_layout_section'] = 'true';
|
||||
$requirements['_layout_builder_access'] = 'view';
|
||||
// Trigger the layout builder RouteEnhancer.
|
||||
$options['_layout_builder'] = TRUE;
|
||||
// Trigger the layout builder param converter.
|
||||
|
@ -92,6 +94,17 @@ trait LayoutBuilderRoutesTrait {
|
|||
->setOptions($options);
|
||||
$collection->add("$route_name_prefix.revert", $route);
|
||||
}
|
||||
elseif (is_subclass_of($definition->getClass(), DefaultsSectionStorageInterface::class)) {
|
||||
$disable_defaults = $defaults;
|
||||
$disable_defaults['_form'] = '\Drupal\layout_builder\Form\LayoutBuilderDisableForm';
|
||||
$disable_options = $options;
|
||||
unset($disable_options['_admin_route'], $disable_options['_layout_builder']);
|
||||
$route = (new Route("$path/disable"))
|
||||
->setDefaults($disable_defaults)
|
||||
->setRequirements($requirements)
|
||||
->setOptions($disable_options);
|
||||
$collection->add("$route_name_prefix.disable", $route);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace Drupal\layout_builder;
|
||||
|
||||
use Drupal\Component\Plugin\PluginInspectionInterface;
|
||||
use Drupal\Core\Access\AccessibleInterface;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
/**
|
||||
|
@ -13,7 +14,7 @@ use Symfony\Component\Routing\RouteCollection;
|
|||
* experimental modules and development releases of contributed modules.
|
||||
* See https://www.drupal.org/core/experimental for more information.
|
||||
*/
|
||||
interface SectionStorageInterface extends SectionListInterface, PluginInspectionInterface {
|
||||
interface SectionStorageInterface extends SectionListInterface, PluginInspectionInterface, AccessibleInterface {
|
||||
|
||||
/**
|
||||
* Returns an identifier for this storage.
|
||||
|
@ -88,10 +89,14 @@ interface SectionStorageInterface extends SectionListInterface, PluginInspection
|
|||
/**
|
||||
* Gets the URL used to display the Layout Builder UI.
|
||||
*
|
||||
* @param string $rel
|
||||
* (optional) The link relationship type, for example: 'view' or 'disable'.
|
||||
* Defaults to 'view'.
|
||||
*
|
||||
* @return \Drupal\Core\Url
|
||||
* The URL object.
|
||||
*/
|
||||
public function getLayoutBuilderUrl();
|
||||
public function getLayoutBuilderUrl($rel = 'view');
|
||||
|
||||
/**
|
||||
* Configures the plugin based on route values.
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Test fixture.
|
||||
*/
|
||||
|
||||
use Drupal\Core\Database\Database;
|
||||
|
||||
$connection = Database::getConnection();
|
||||
|
||||
// Add a layout plugin to an existing entity view display without explicitly
|
||||
// enabling Layout Builder for this display.
|
||||
$display = $connection->select('config')
|
||||
->fields('config', ['data'])
|
||||
->condition('collection', '')
|
||||
->condition('name', 'core.entity_view_display.block_content.basic.default')
|
||||
->execute()
|
||||
->fetchField();
|
||||
$display = unserialize($display);
|
||||
$display['third_party_settings']['layout_builder']['sections'][] = [
|
||||
'layout_id' => 'layout_onecol',
|
||||
'layout_settings' => [],
|
||||
'components' => [
|
||||
'some-uuid' => [
|
||||
'uuid' => 'some-uuid',
|
||||
'region' => 'content',
|
||||
'configuration' => [
|
||||
'id' => 'system_powered_by_block',
|
||||
],
|
||||
'additional' => [],
|
||||
'weight' => 0,
|
||||
],
|
||||
],
|
||||
];
|
||||
$connection->update('config')
|
||||
->fields([
|
||||
'data' => serialize($display),
|
||||
'collection' => '',
|
||||
'name' => 'core.entity_view_display.block_content.basic.default',
|
||||
])
|
||||
->condition('collection', '')
|
||||
->condition('name', 'core.entity_view_display.block_content.basic.default')
|
||||
->execute();
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Test fixture.
|
||||
*/
|
||||
|
||||
use Drupal\Core\Database\Database;
|
||||
|
||||
$connection = Database::getConnection();
|
||||
|
||||
// Enable Layout Builder on an existing entity view display.
|
||||
$display = $connection->select('config')
|
||||
->fields('config', ['data'])
|
||||
->condition('collection', '')
|
||||
->condition('name', 'core.entity_view_display.node.article.default')
|
||||
->execute()
|
||||
->fetchField();
|
||||
$display = unserialize($display);
|
||||
$display['third_party_settings']['layout_builder']['enabled'] = TRUE;
|
||||
$connection->update('config')
|
||||
->fields([
|
||||
'data' => serialize($display),
|
||||
'collection' => '',
|
||||
'name' => 'core.entity_view_display.node.article.default',
|
||||
])
|
||||
->condition('collection', '')
|
||||
->condition('name', 'core.entity_view_display.node.article.default')
|
||||
->execute();
|
|
@ -9,6 +9,17 @@ use Drupal\Core\Database\Database;
|
|||
|
||||
$connection = Database::getConnection();
|
||||
|
||||
// Set the schema version.
|
||||
$connection->merge('key_value')
|
||||
->fields([
|
||||
'value' => 'i:8000;',
|
||||
'name' => 'layout_builder',
|
||||
'collection' => 'system.schema',
|
||||
])
|
||||
->condition('collection', 'system.schema')
|
||||
->condition('name', 'layout_builder')
|
||||
->execute();
|
||||
|
||||
// Update core.extension.
|
||||
$extensions = $connection->select('config')
|
||||
->fields('config', ['data'])
|
||||
|
|
|
@ -80,6 +80,10 @@ class LayoutBuilderTest extends BrowserTestBase {
|
|||
|
||||
// From the manage display page, go to manage the layout.
|
||||
$this->drupalGet("$field_ui_prefix/display/default");
|
||||
$assert_session->linkNotExists('Manage layout');
|
||||
$assert_session->fieldDisabled('layout[allow_custom]');
|
||||
|
||||
$this->drupalPostForm(NULL, ['layout[enabled]' => TRUE], 'Save');
|
||||
$assert_session->linkExists('Manage layout');
|
||||
$this->clickLink('Manage layout');
|
||||
$assert_session->addressEquals("$field_ui_prefix/display-layout/default");
|
||||
|
@ -153,6 +157,7 @@ class LayoutBuilderTest extends BrowserTestBase {
|
|||
|
||||
// Assert that overrides cannot be turned off while overrides exist.
|
||||
$this->drupalGet("$field_ui_prefix/display/default");
|
||||
$assert_session->checkboxChecked('layout[allow_custom]');
|
||||
$assert_session->fieldDisabled('layout[allow_custom]');
|
||||
|
||||
// Alter the defaults.
|
||||
|
@ -243,7 +248,9 @@ class LayoutBuilderTest extends BrowserTestBase {
|
|||
$page->fillField('id', 'myothermenu');
|
||||
$page->pressButton('Save');
|
||||
|
||||
$this->drupalGet('admin/structure/types/manage/bundle_with_section_field/display-layout/default');
|
||||
$this->drupalPostForm('admin/structure/types/manage/bundle_with_section_field/display', ['layout[enabled]' => TRUE], 'Save');
|
||||
$assert_session->linkExists('Manage layout');
|
||||
$this->clickLink('Manage layout');
|
||||
$assert_session->linkExists('Add Section');
|
||||
$this->clickLink('Add Section');
|
||||
$assert_session->linkExists('Layout plugin (with dependencies)');
|
||||
|
@ -305,6 +312,7 @@ class LayoutBuilderTest extends BrowserTestBase {
|
|||
|
||||
$field_ui_prefix = 'admin/structure/types/manage/bundle_with_section_field';
|
||||
// Allow overrides for the layout.
|
||||
$this->drupalPostForm("$field_ui_prefix/display/default", ['layout[enabled]' => TRUE], 'Save');
|
||||
$this->drupalPostForm("$field_ui_prefix/display/default", ['layout[allow_custom]' => TRUE], 'Save');
|
||||
|
||||
// Customize the default view mode.
|
||||
|
@ -365,7 +373,8 @@ class LayoutBuilderTest extends BrowserTestBase {
|
|||
]));
|
||||
|
||||
// From the manage display page, go to manage the layout.
|
||||
$this->drupalGet('admin/structure/types/manage/bundle_with_section_field/display/default');
|
||||
$this->drupalPostForm('admin/structure/types/manage/bundle_with_section_field/display/default', ['layout[enabled]' => TRUE], 'Save');
|
||||
$assert_session->linkExists('Manage layout');
|
||||
$this->clickLink('Manage layout');
|
||||
|
||||
// Add a new block.
|
||||
|
@ -412,6 +421,7 @@ class LayoutBuilderTest extends BrowserTestBase {
|
|||
|
||||
$field_ui_prefix = 'admin/structure/types/manage/bundle_with_section_field';
|
||||
// Enable overrides.
|
||||
$this->drupalPostForm("$field_ui_prefix/display/default", ['layout[enabled]' => TRUE], 'Save');
|
||||
$this->drupalPostForm("$field_ui_prefix/display/default", ['layout[allow_custom]' => TRUE], 'Save');
|
||||
$this->drupalGet('node/1');
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ class LayoutSectionTest extends BrowserTestBase {
|
|||
]);
|
||||
|
||||
LayoutBuilderEntityViewDisplay::load('node.bundle_with_section_field.default')
|
||||
->enableLayoutBuilder()
|
||||
->setOverridable()
|
||||
->save();
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ class ExtraFieldUpdatePathTest extends UpdatePathTestBase {
|
|||
$this->databaseDumpFiles = [
|
||||
__DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8.4.0.bare.standard.php.gz',
|
||||
__DIR__ . '/../../../fixtures/update/layout-builder.php',
|
||||
__DIR__ . '/../../../fixtures/update/layout-builder-extra.php',
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -27,15 +28,26 @@ class ExtraFieldUpdatePathTest extends UpdatePathTestBase {
|
|||
* Tests the upgrade path for Layout Builder extra fields.
|
||||
*/
|
||||
public function testRunUpdates() {
|
||||
// The default view mode has Layout Builder enabled.
|
||||
$data = EntityViewDisplay::load('node.article.default')->toArray();
|
||||
$this->assertArrayHasKey('third_party_settings', $data);
|
||||
$this->assertArrayNotHasKey('sections', $data['third_party_settings']['layout_builder']);
|
||||
|
||||
// The teaser view mode does not have Layout Builder enabled.
|
||||
$data = EntityViewDisplay::load('node.article.teaser')->toArray();
|
||||
$this->assertArrayNotHasKey('third_party_settings', $data);
|
||||
|
||||
$this->runUpdates();
|
||||
|
||||
$data = EntityViewDisplay::load('node.article.teaser')->toArray();
|
||||
// The extra links have been added.
|
||||
$data = EntityViewDisplay::load('node.article.default')->toArray();
|
||||
$components = $data['third_party_settings']['layout_builder']['sections'][0]->getComponents();
|
||||
$component = reset($components);
|
||||
$this->assertSame('extra_field_block:node:article:links', $component->getPluginId());
|
||||
|
||||
// No extra links have been added.
|
||||
$data = EntityViewDisplay::load('node.article.teaser')->toArray();
|
||||
$this->assertArrayNotHasKey('third_party_settings', $data);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\layout_builder\Functional\Update;
|
||||
|
||||
use Drupal\FunctionalTests\Update\UpdatePathTestBase;
|
||||
|
||||
/**
|
||||
* Tests the upgrade path for enabling Layout Builder.
|
||||
*
|
||||
* @see layout_builder_update_8601()
|
||||
*
|
||||
* @group layout_builder
|
||||
* @group legacy
|
||||
*/
|
||||
class LayoutBuilderEnableUpdatePathTest extends UpdatePathTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setDatabaseDumpFiles() {
|
||||
$this->databaseDumpFiles = [
|
||||
__DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8.4.0.bare.standard.php.gz',
|
||||
__DIR__ . '/../../../fixtures/update/layout-builder.php',
|
||||
__DIR__ . '/../../../fixtures/update/layout-builder-enable.php',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the upgrade path for enabling Layout Builder.
|
||||
*/
|
||||
public function testRunUpdates() {
|
||||
$assert_session = $this->assertSession();
|
||||
|
||||
$expected = [
|
||||
'sections' => [
|
||||
[
|
||||
'layout_id' => 'layout_onecol',
|
||||
'layout_settings' => [],
|
||||
'components' => [
|
||||
'some-uuid' => [
|
||||
'uuid' => 'some-uuid',
|
||||
'region' => 'content',
|
||||
'configuration' => [
|
||||
'id' => 'system_powered_by_block',
|
||||
],
|
||||
'additional' => [],
|
||||
'weight' => 0,
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
$this->assertLayoutBuilderSettings($expected, 'block_content', 'basic', 'default');
|
||||
$this->assertLayoutBuilderSettings(NULL, 'node', 'page', 'default');
|
||||
|
||||
$this->runUpdates();
|
||||
|
||||
// The display with existing sections is enabled while the other is not.
|
||||
$expected['enabled'] = TRUE;
|
||||
$this->assertLayoutBuilderSettings($expected, 'block_content', 'basic', 'default');
|
||||
$this->assertLayoutBuilderSettings(NULL, 'node', 'page', 'default');
|
||||
|
||||
$this->drupalLogin($this->rootUser);
|
||||
$this->drupalGet('admin/structure/block/block-content/manage/basic/display');
|
||||
$assert_session->checkboxChecked('layout[enabled]');
|
||||
$this->drupalGet('admin/structure/types/manage/page/display');
|
||||
$assert_session->checkboxNotChecked('layout[enabled]');
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts the Layout Builder settings for a given display.
|
||||
*
|
||||
* @param mixed $expected
|
||||
* The expected value.
|
||||
* @param string $entity_type_id
|
||||
* The entity type ID.
|
||||
* @param string $bundle
|
||||
* The bundle.
|
||||
* @param string $view_mode
|
||||
* The view mode.
|
||||
*/
|
||||
protected function assertLayoutBuilderSettings($expected, $entity_type_id, $bundle, $view_mode) {
|
||||
$this->assertEquals($expected, \Drupal::config("core.entity_view_display.$entity_type_id.$bundle.$view_mode")->get('third_party_settings.layout_builder'));
|
||||
}
|
||||
|
||||
}
|
|
@ -60,7 +60,7 @@ class AjaxBlockTest extends WebDriverTestBase {
|
|||
$field_ui_prefix = 'admin/structure/types/manage/bundle_with_section_field';
|
||||
|
||||
// From the manage display page, go to manage the layout.
|
||||
$this->drupalGet("$field_ui_prefix/display/default");
|
||||
$this->drupalPostForm("$field_ui_prefix/display/default", ['layout[enabled]' => TRUE], 'Save');
|
||||
$assert_session->linkExists('Manage layout');
|
||||
$this->clickLink('Manage layout');
|
||||
$assert_session->addressEquals("$field_ui_prefix/display-layout/default");
|
||||
|
|
|
@ -44,7 +44,10 @@ class ItemLayoutFieldBlockTest extends WebDriverTestBase {
|
|||
$page = $this->getSession()->getPage();
|
||||
|
||||
// Allow overrides for the layout.
|
||||
$this->drupalPostForm('admin/structure/types/manage/bundle_with_layout_overrides/display/default', ['layout[allow_custom]' => TRUE], 'Save');
|
||||
$this->drupalGet('admin/structure/types/manage/bundle_with_layout_overrides/display/default');
|
||||
$page->checkField('layout[enabled]');
|
||||
$page->checkField('layout[allow_custom]');
|
||||
$page->pressButton('Save');
|
||||
|
||||
// Start by creating a node of type with layout overrides.
|
||||
$node = $this->createNode([
|
||||
|
|
|
@ -0,0 +1,184 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\layout_builder\FunctionalJavascript;
|
||||
|
||||
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
|
||||
|
||||
/**
|
||||
* Tests the ability for opting in and out of Layout Builder.
|
||||
*
|
||||
* @group layout_builder
|
||||
*/
|
||||
class LayoutBuilderOptInTest extends WebDriverTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'node',
|
||||
'field_ui',
|
||||
'block',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// @todo The Layout Builder UI relies on local tasks; fix in
|
||||
// https://www.drupal.org/project/drupal/issues/2917777.
|
||||
$this->drupalPlaceBlock('local_tasks_block');
|
||||
|
||||
// Create one content type before installing Layout Builder and one after.
|
||||
$this->createContentType(['type' => 'before']);
|
||||
$this->container->get('module_installer')->install(['layout_builder']);
|
||||
$this->rebuildAll();
|
||||
$this->createContentType(['type' => 'after']);
|
||||
|
||||
$this->drupalLogin($this->drupalCreateUser([
|
||||
'configure any layout',
|
||||
'administer node display',
|
||||
]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the interaction between the two layout checkboxes.
|
||||
*/
|
||||
public function testCheckboxLogic() {
|
||||
$assert_session = $this->assertSession();
|
||||
$page = $this->getSession()->getPage();
|
||||
|
||||
$this->drupalGet('admin/structure/types/manage/before/display/default');
|
||||
// Both fields are unchecked and allow_custom is disabled and hidden.
|
||||
$assert_session->checkboxNotChecked('layout[enabled]');
|
||||
$assert_session->checkboxNotChecked('layout[allow_custom]');
|
||||
$assert_session->fieldDisabled('layout[allow_custom]');
|
||||
$this->assertFalse($page->findField('layout[allow_custom]')->isVisible());
|
||||
|
||||
// Checking is_enable will show allow_custom.
|
||||
$page->checkField('layout[enabled]');
|
||||
$assert_session->checkboxNotChecked('layout[allow_custom]');
|
||||
$this->assertTrue($page->findField('layout[allow_custom]')->isVisible());
|
||||
$page->pressButton('Save');
|
||||
$assert_session->checkboxChecked('layout[enabled]');
|
||||
$assert_session->checkboxNotChecked('layout[allow_custom]');
|
||||
|
||||
// Check and submit allow_custom.
|
||||
$page->checkField('layout[allow_custom]');
|
||||
$page->pressButton('Save');
|
||||
$assert_session->checkboxChecked('layout[enabled]');
|
||||
$assert_session->checkboxChecked('layout[allow_custom]');
|
||||
|
||||
// Reset the checkboxes.
|
||||
$page->uncheckField('layout[enabled]');
|
||||
$page->pressButton('Save');
|
||||
$page->pressButton('Confirm');
|
||||
$assert_session->checkboxNotChecked('layout[enabled]');
|
||||
$assert_session->checkboxNotChecked('layout[allow_custom]');
|
||||
|
||||
// Check both at the same time.
|
||||
$page->checkField('layout[enabled]');
|
||||
$page->checkField('layout[allow_custom]');
|
||||
$page->pressButton('Save');
|
||||
$assert_session->checkboxChecked('layout[enabled]');
|
||||
$assert_session->checkboxChecked('layout[allow_custom]');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the expected default values for enabling Layout Builder.
|
||||
*/
|
||||
public function testDefaultValues() {
|
||||
$assert_session = $this->assertSession();
|
||||
$page = $this->getSession()->getPage();
|
||||
|
||||
// Both the content type created before and after Layout Builder was
|
||||
// installed is still using the Field UI.
|
||||
$this->drupalGet('admin/structure/types/manage/before/display/default');
|
||||
$assert_session->checkboxNotChecked('layout[enabled]');
|
||||
|
||||
$field_ui_prefix = 'admin/structure/types/manage/after/display/default';
|
||||
$this->drupalGet($field_ui_prefix);
|
||||
$assert_session->checkboxNotChecked('layout[enabled]');
|
||||
$page->checkField('layout[enabled]');
|
||||
$page->pressButton('Save');
|
||||
|
||||
$layout_builder_ui = $this->getPathForFieldBlock('node', 'after', 'default', 'body');
|
||||
|
||||
$assert_session->linkExists('Manage layout');
|
||||
$this->clickLink('Manage layout');
|
||||
// Ensure the body appears once and only once.
|
||||
$assert_session->elementsCount('css', '.field--name-body', 1);
|
||||
|
||||
// Change the body formatter to Trimmed.
|
||||
$this->drupalGet($layout_builder_ui);
|
||||
$assert_session->fieldValueEquals('settings[formatter][type]', 'text_default');
|
||||
$page->selectFieldOption('settings[formatter][type]', 'text_trimmed');
|
||||
$assert_session->assertWaitOnAjaxRequest();
|
||||
$page->pressButton('Update');
|
||||
$assert_session->linkExists('Save Layout');
|
||||
$this->clickLink('Save Layout');
|
||||
|
||||
$this->drupalGet($layout_builder_ui);
|
||||
$assert_session->fieldValueEquals('settings[formatter][type]', 'text_trimmed');
|
||||
|
||||
// Disable Layout Builder.
|
||||
$this->drupalPostForm($field_ui_prefix, ['layout[enabled]' => FALSE], 'Save');
|
||||
$page->pressButton('Confirm');
|
||||
|
||||
// The Layout Builder UI is no longer accessible.
|
||||
$this->drupalGet($layout_builder_ui);
|
||||
$assert_session->pageTextContains('You are not authorized to access this page.');
|
||||
|
||||
// The original body formatter is reflected in Field UI.
|
||||
$this->drupalGet($field_ui_prefix);
|
||||
$assert_session->fieldValueEquals('fields[body][type]', 'text_default');
|
||||
|
||||
// Change the body formatter to Summary.
|
||||
$page->selectFieldOption('fields[body][type]', 'text_summary_or_trimmed');
|
||||
$assert_session->assertWaitOnAjaxRequest();
|
||||
$page->pressButton('Save');
|
||||
$assert_session->fieldValueEquals('fields[body][type]', 'text_summary_or_trimmed');
|
||||
|
||||
// Reactivate Layout Builder.
|
||||
$this->drupalPostForm($field_ui_prefix, ['layout[enabled]' => TRUE], 'Save');
|
||||
$assert_session->linkExists('Manage layout');
|
||||
$this->clickLink('Manage layout');
|
||||
// Ensure the body appears once and only once.
|
||||
$assert_session->elementsCount('css', '.field--name-body', 1);
|
||||
|
||||
// The changed body formatter is reflected in Layout Builder UI.
|
||||
$this->drupalGet($this->getPathForFieldBlock('node', 'after', 'default', 'body'));
|
||||
$assert_session->fieldValueEquals('settings[formatter][type]', 'text_summary_or_trimmed');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path to update a field block in the UI.
|
||||
*
|
||||
* @param string $entity_type_id
|
||||
* The entity type ID.
|
||||
* @param string $bundle
|
||||
* The bundle.
|
||||
* @param string $view_mode
|
||||
* The view mode.
|
||||
* @param string $field_name
|
||||
* The field name.
|
||||
*
|
||||
* @return string
|
||||
* The path.
|
||||
*/
|
||||
protected function getPathForFieldBlock($entity_type_id, $bundle, $view_mode, $field_name) {
|
||||
$delta = 0;
|
||||
/** @var \Drupal\layout_builder\Entity\LayoutEntityDisplayInterface $display */
|
||||
$display = $this->container->get('entity_type.manager')->getStorage('entity_view_display')->load("$entity_type_id.$bundle.$view_mode");
|
||||
$body_component = NULL;
|
||||
foreach ($display->getSection($delta)->getComponents() as $component) {
|
||||
if ($component->getPluginId() === "field_block:$entity_type_id:$bundle:$field_name") {
|
||||
$body_component = $component;
|
||||
}
|
||||
}
|
||||
$this->assertNotNull($body_component);
|
||||
return 'layout_builder/update/block/defaults/node.after.default/0/content/' . $body_component->getUuid();
|
||||
}
|
||||
|
||||
}
|
|
@ -23,7 +23,7 @@ abstract class LayoutBuilderCompatibilityTestBase extends EntityKernelTestBase {
|
|||
/**
|
||||
* The entity view display.
|
||||
*
|
||||
* @var \Drupal\field_layout\Display\EntityDisplayWithLayoutInterface
|
||||
* @var \Drupal\layout_builder\Entity\LayoutEntityDisplayInterface
|
||||
*/
|
||||
protected $display;
|
||||
|
||||
|
@ -86,13 +86,21 @@ abstract class LayoutBuilderCompatibilityTestBase extends EntityKernelTestBase {
|
|||
/**
|
||||
* Installs the Layout Builder.
|
||||
*
|
||||
* Also configures and reloads the entity display, and reloads the entity.
|
||||
* Also configures and reloads the entity display.
|
||||
*/
|
||||
protected function installLayoutBuilder() {
|
||||
$this->container->get('module_installer')->install(['layout_builder']);
|
||||
$this->refreshServices();
|
||||
|
||||
$this->display = $this->reloadEntity($this->display);
|
||||
$this->display->enableLayoutBuilder()->save();
|
||||
$this->entity = $this->reloadEntity($this->entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables overrides for the display and reloads the entity.
|
||||
*/
|
||||
protected function enableOverrides() {
|
||||
$this->display->setOverridable()->save();
|
||||
$this->entity = $this->reloadEntity($this->entity);
|
||||
}
|
||||
|
|
|
@ -54,6 +54,7 @@ class LayoutBuilderFieldLayoutCompatibilityTest extends LayoutBuilderCompatibili
|
|||
$this->assertFieldAttributes($this->entity, $expected_fields);
|
||||
|
||||
// Add a layout override.
|
||||
$this->enableOverrides();
|
||||
/** @var \Drupal\layout_builder\SectionStorageInterface $field_list */
|
||||
$field_list = $this->entity->get('layout_builder__layout');
|
||||
$field_list->appendSection(new Section('layout_onecol'));
|
||||
|
|
|
@ -33,6 +33,8 @@ class LayoutBuilderInstallTest extends LayoutBuilderCompatibilityTestBase {
|
|||
$this->assertFieldAttributes($this->entity, $expected_fields);
|
||||
|
||||
// Add a layout override.
|
||||
$this->enableOverrides();
|
||||
$this->entity = $this->reloadEntity($this->entity);
|
||||
$this->entity->get('layout_builder__layout')->appendSection(new Section('layout_onecol'));
|
||||
$this->entity->save();
|
||||
|
||||
|
|
|
@ -32,7 +32,10 @@ class LayoutSectionItemListTest extends SectionStorageTestBase {
|
|||
'bundle' => 'entity_test_base_field_display',
|
||||
'mode' => 'default',
|
||||
'status' => TRUE,
|
||||
])->setOverridable()->save();
|
||||
])
|
||||
->enableLayoutBuilder()
|
||||
->setOverridable()
|
||||
->save();
|
||||
|
||||
array_map(function ($row) {
|
||||
return ['section' => $row];
|
||||
|
|
|
@ -254,6 +254,7 @@ class DefaultsSectionStorageTest extends UnitTestCase {
|
|||
[
|
||||
'_field_ui_view_mode_access' => 'administer with_bundle_key display',
|
||||
'_has_layout_section' => 'true',
|
||||
'_layout_builder_access' => 'view',
|
||||
],
|
||||
[
|
||||
'parameters' => [
|
||||
|
@ -275,6 +276,7 @@ class DefaultsSectionStorageTest extends UnitTestCase {
|
|||
[
|
||||
'_field_ui_view_mode_access' => 'administer with_bundle_key display',
|
||||
'_has_layout_section' => 'true',
|
||||
'_layout_builder_access' => 'view',
|
||||
],
|
||||
[
|
||||
'parameters' => [
|
||||
|
@ -296,6 +298,7 @@ class DefaultsSectionStorageTest extends UnitTestCase {
|
|||
[
|
||||
'_field_ui_view_mode_access' => 'administer with_bundle_key display',
|
||||
'_has_layout_section' => 'true',
|
||||
'_layout_builder_access' => 'view',
|
||||
],
|
||||
[
|
||||
'parameters' => [
|
||||
|
@ -305,6 +308,26 @@ class DefaultsSectionStorageTest extends UnitTestCase {
|
|||
'_admin_route' => FALSE,
|
||||
]
|
||||
),
|
||||
'layout_builder.defaults.with_bundle_key.disable' => new Route(
|
||||
'/admin/entity/whatever/display-layout/{view_mode_name}/disable',
|
||||
[
|
||||
'entity_type_id' => 'with_bundle_key',
|
||||
'bundle_key' => 'my_bundle_type',
|
||||
'section_storage_type' => 'defaults',
|
||||
'section_storage' => '',
|
||||
'_form' => '\Drupal\layout_builder\Form\LayoutBuilderDisableForm',
|
||||
],
|
||||
[
|
||||
'_field_ui_view_mode_access' => 'administer with_bundle_key display',
|
||||
'_has_layout_section' => 'true',
|
||||
'_layout_builder_access' => 'view',
|
||||
],
|
||||
[
|
||||
'parameters' => [
|
||||
'section_storage' => ['layout_builder_tempstore' => TRUE],
|
||||
],
|
||||
]
|
||||
),
|
||||
'layout_builder.defaults.with_bundle_parameter.view' => new Route(
|
||||
'/admin/entity/{bundle}/display-layout/{view_mode_name}',
|
||||
[
|
||||
|
@ -318,6 +341,7 @@ class DefaultsSectionStorageTest extends UnitTestCase {
|
|||
[
|
||||
'_field_ui_view_mode_access' => 'administer with_bundle_parameter display',
|
||||
'_has_layout_section' => 'true',
|
||||
'_layout_builder_access' => 'view',
|
||||
],
|
||||
[
|
||||
'parameters' => [
|
||||
|
@ -338,6 +362,7 @@ class DefaultsSectionStorageTest extends UnitTestCase {
|
|||
[
|
||||
'_field_ui_view_mode_access' => 'administer with_bundle_parameter display',
|
||||
'_has_layout_section' => 'true',
|
||||
'_layout_builder_access' => 'view',
|
||||
],
|
||||
[
|
||||
'parameters' => [
|
||||
|
@ -358,6 +383,7 @@ class DefaultsSectionStorageTest extends UnitTestCase {
|
|||
[
|
||||
'_field_ui_view_mode_access' => 'administer with_bundle_parameter display',
|
||||
'_has_layout_section' => 'true',
|
||||
'_layout_builder_access' => 'view',
|
||||
],
|
||||
[
|
||||
'parameters' => [
|
||||
|
@ -367,6 +393,25 @@ class DefaultsSectionStorageTest extends UnitTestCase {
|
|||
'_admin_route' => FALSE,
|
||||
]
|
||||
),
|
||||
'layout_builder.defaults.with_bundle_parameter.disable' => new Route(
|
||||
'/admin/entity/{bundle}/display-layout/{view_mode_name}/disable',
|
||||
[
|
||||
'entity_type_id' => 'with_bundle_parameter',
|
||||
'section_storage_type' => 'defaults',
|
||||
'section_storage' => '',
|
||||
'_form' => '\Drupal\layout_builder\Form\LayoutBuilderDisableForm',
|
||||
],
|
||||
[
|
||||
'_field_ui_view_mode_access' => 'administer with_bundle_parameter display',
|
||||
'_has_layout_section' => 'true',
|
||||
'_layout_builder_access' => 'view',
|
||||
],
|
||||
[
|
||||
'parameters' => [
|
||||
'section_storage' => ['layout_builder_tempstore' => TRUE],
|
||||
],
|
||||
]
|
||||
),
|
||||
];
|
||||
|
||||
$collection = new RouteCollection();
|
||||
|
|
|
@ -223,6 +223,7 @@ class OverridesSectionStorageTest extends UnitTestCase {
|
|||
],
|
||||
[
|
||||
'_has_layout_section' => 'true',
|
||||
'_layout_builder_access' => 'view',
|
||||
],
|
||||
[
|
||||
'parameters' => [
|
||||
|
@ -242,6 +243,7 @@ class OverridesSectionStorageTest extends UnitTestCase {
|
|||
],
|
||||
[
|
||||
'_has_layout_section' => 'true',
|
||||
'_layout_builder_access' => 'view',
|
||||
],
|
||||
[
|
||||
'parameters' => [
|
||||
|
@ -261,6 +263,7 @@ class OverridesSectionStorageTest extends UnitTestCase {
|
|||
],
|
||||
[
|
||||
'_has_layout_section' => 'true',
|
||||
'_layout_builder_access' => 'view',
|
||||
],
|
||||
[
|
||||
'parameters' => [
|
||||
|
@ -280,6 +283,7 @@ class OverridesSectionStorageTest extends UnitTestCase {
|
|||
],
|
||||
[
|
||||
'_has_layout_section' => 'true',
|
||||
'_layout_builder_access' => 'view',
|
||||
],
|
||||
[
|
||||
'parameters' => [
|
||||
|
@ -301,6 +305,7 @@ class OverridesSectionStorageTest extends UnitTestCase {
|
|||
],
|
||||
[
|
||||
'_has_layout_section' => 'true',
|
||||
'_layout_builder_access' => 'view',
|
||||
'with_integer_id' => '\d+',
|
||||
],
|
||||
[
|
||||
|
@ -321,6 +326,7 @@ class OverridesSectionStorageTest extends UnitTestCase {
|
|||
],
|
||||
[
|
||||
'_has_layout_section' => 'true',
|
||||
'_layout_builder_access' => 'view',
|
||||
'with_integer_id' => '\d+',
|
||||
],
|
||||
[
|
||||
|
@ -341,6 +347,7 @@ class OverridesSectionStorageTest extends UnitTestCase {
|
|||
],
|
||||
[
|
||||
'_has_layout_section' => 'true',
|
||||
'_layout_builder_access' => 'view',
|
||||
'with_integer_id' => '\d+',
|
||||
],
|
||||
[
|
||||
|
@ -361,6 +368,7 @@ class OverridesSectionStorageTest extends UnitTestCase {
|
|||
],
|
||||
[
|
||||
'_has_layout_section' => 'true',
|
||||
'_layout_builder_access' => 'view',
|
||||
'with_integer_id' => '\d+',
|
||||
],
|
||||
[
|
||||
|
|
Loading…
Reference in New Issue