diff --git a/core/modules/layout_builder/config/install/layout_builder.settings.yml b/core/modules/layout_builder/config/install/layout_builder.settings.yml new file mode 100644 index 0000000000000000000000000000000000000000..43521763c7b16707186c8ac880f7783bce13d04b --- /dev/null +++ b/core/modules/layout_builder/config/install/layout_builder.settings.yml @@ -0,0 +1 @@ +expose_all_field_blocks: false diff --git a/core/modules/layout_builder/config/schema/layout_builder.schema.yml b/core/modules/layout_builder/config/schema/layout_builder.schema.yml index 0786286f1f9cae4276a94d1194552754789f02dd..46c12e0b0b14f0f80abe383e900a75dd9ffc71d7 100644 --- a/core/modules/layout_builder/config/schema/layout_builder.schema.yml +++ b/core/modules/layout_builder/config/schema/layout_builder.schema.yml @@ -86,3 +86,11 @@ layout_plugin.settings.layout_twocol_section: layout_plugin.settings.layout_threecol_section: type: layout_builder_multi_width + +layout_builder.settings: + type: config_object + label: 'Layout builder settings' + mapping: + expose_all_field_blocks: + type: boolean + label: 'Expose all field blocks' diff --git a/core/modules/layout_builder/layout_builder.info.yml b/core/modules/layout_builder/layout_builder.info.yml index 0a6e43ea3b280c099666c2f066a3be37165b7b9c..f54c8df3639f411a3687dcabe6a040f1522b5d03 100644 --- a/core/modules/layout_builder/layout_builder.info.yml +++ b/core/modules/layout_builder/layout_builder.info.yml @@ -1,6 +1,7 @@ name: 'Layout Builder' type: module description: 'Allows users to add and arrange blocks and content fields directly on the content.' +configure: layout_builder.settings package: Core version: VERSION dependencies: diff --git a/core/modules/layout_builder/layout_builder.links.menu.yml b/core/modules/layout_builder/layout_builder.links.menu.yml new file mode 100644 index 0000000000000000000000000000000000000000..018db609688ee95affafd6e81772191174e7a641 --- /dev/null +++ b/core/modules/layout_builder/layout_builder.links.menu.yml @@ -0,0 +1,5 @@ +layout_builder.settings: + title: 'Layout Builder' + parent: system.admin_config_content + description: 'Configure Layout Builder settings.' + route_name: layout_builder.settings diff --git a/core/modules/layout_builder/layout_builder.permissions.yml b/core/modules/layout_builder/layout_builder.permissions.yml index 5799cb652b84ab4cf79b54207b9598256ae5b738..562524dd002eda21737ae451f59fee3a1ac3473f 100644 --- a/core/modules/layout_builder/layout_builder.permissions.yml +++ b/core/modules/layout_builder/layout_builder.permissions.yml @@ -1,3 +1,6 @@ +administer layout builder: + title: 'Administer layout builder' + restrict access: true configure any layout: title: 'Configure any layout' restrict access: true diff --git a/core/modules/layout_builder/layout_builder.post_update.php b/core/modules/layout_builder/layout_builder.post_update.php index 5d500ddd0f4146a5943fbabbf192c67cce33af9a..87a5de85f38f2120fe67ddff8bd155087644fa79 100644 --- a/core/modules/layout_builder/layout_builder.post_update.php +++ b/core/modules/layout_builder/layout_builder.post_update.php @@ -69,3 +69,12 @@ function layout_builder_post_update_timestamp_formatter(array &$sandbox = NULL): return $update; }); } + +/** + * Configure the default expose all fields setting. + */ +function layout_builder_post_update_default_expose_field_block_setting(): void { + \Drupal::configFactory()->getEditable('layout_builder.settings') + ->set('expose_all_field_blocks', TRUE) + ->save(TRUE); +} diff --git a/core/modules/layout_builder/layout_builder.routing.yml b/core/modules/layout_builder/layout_builder.routing.yml index fa72dcec931f8cec5fb139e35addba1618e4d9ff..88b3739c3f1c6d76b5bafd74f2340fd32ef7e2ef 100644 --- a/core/modules/layout_builder/layout_builder.routing.yml +++ b/core/modules/layout_builder/layout_builder.routing.yml @@ -1,3 +1,11 @@ +layout_builder.settings: + path: '/admin/config/content/layout-builder' + defaults: + _form: '\Drupal\layout_builder\Form\LayoutBuilderSettingsForm' + _title: 'Layout Builder' + requirements: + _permission: 'administer layout builder' + layout_builder.choose_section: path: '/layout_builder/choose/section/{section_storage_type}/{section_storage}/{delta}' defaults: diff --git a/core/modules/layout_builder/layout_builder.services.yml b/core/modules/layout_builder/layout_builder.services.yml index 65c93652209b5e6f814d8756fb35264428a8539f..9db2a0919aba515be6e6ecc110ea9053db902dfc 100644 --- a/core/modules/layout_builder/layout_builder.services.yml +++ b/core/modules/layout_builder/layout_builder.services.yml @@ -68,3 +68,6 @@ services: layout_builder.element.prepare_layout: class: Drupal\layout_builder\EventSubscriber\PrepareLayout arguments: ['@layout_builder.tempstore_repository', '@messenger'] + layout_builder.config_subscriber: + class: Drupal\layout_builder\EventSubscriber\LayoutBuilderConfigSubscriber + arguments: ['@plugin.manager.block'] diff --git a/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplay.php b/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplay.php index dd1462eea13ace40e5e8989e3662e658ff8be5c0..c4f89b0caec0c84650c8b45da637d23f0116705f 100644 --- a/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplay.php +++ b/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplay.php @@ -159,6 +159,19 @@ public function preSave(EntityStorageInterface $storage) { } } + /** + * {@inheritdoc} + */ + public function save(): int { + $return = parent::save(); + if (!\Drupal::config('layout_builder.settings')->get('expose_all_field_blocks')) { + // Invalidate the block cache in order to regenerate field block + // definitions. + \Drupal::service('plugin.manager.block')->clearCachedDefinitions(); + } + return $return; + } + /** * Removes a layout section field if it is no longer needed. * diff --git a/core/modules/layout_builder/src/EventSubscriber/LayoutBuilderConfigSubscriber.php b/core/modules/layout_builder/src/EventSubscriber/LayoutBuilderConfigSubscriber.php new file mode 100644 index 0000000000000000000000000000000000000000..cb681724664ef316e4c3e8c72da6983f1e3ffe7f --- /dev/null +++ b/core/modules/layout_builder/src/EventSubscriber/LayoutBuilderConfigSubscriber.php @@ -0,0 +1,46 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\layout_builder\EventSubscriber; + +use Drupal\Core\Block\BlockManagerInterface; +use Drupal\Core\Config\ConfigCrudEvent; +use Drupal\Core\Config\ConfigEvents; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; + +/** + * Layout Builder Config subscriber. + */ +final class LayoutBuilderConfigSubscriber implements EventSubscriberInterface { + + /** + * Constructs a LayoutBuilderConfigSubscriber. + */ + public function __construct( + protected BlockManagerInterface $blockManager, + ) { + } + + /** + * Clears the block plugin cache when expose_all_field_blocks changes. + * + * @param \Drupal\Core\Config\ConfigCrudEvent $event + * The configuration event. + */ + public function onConfigSave(ConfigCrudEvent $event): void { + $saved_config = $event->getConfig(); + if ($saved_config->getName() == 'layout_builder.settings' && $event->isChanged('expose_all_field_blocks')) { + $this->blockManager->clearCachedDefinitions(); + } + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents(): array { + $events[ConfigEvents::SAVE][] = ['onConfigSave']; + return $events; + } + +} diff --git a/core/modules/layout_builder/src/Form/LayoutBuilderSettingsForm.php b/core/modules/layout_builder/src/Form/LayoutBuilderSettingsForm.php new file mode 100644 index 0000000000000000000000000000000000000000..6a96b39fb942b486d44a6bbe6099495352c15c41 --- /dev/null +++ b/core/modules/layout_builder/src/Form/LayoutBuilderSettingsForm.php @@ -0,0 +1,40 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\layout_builder\Form; + +use Drupal\Core\Form\ConfigFormBase; +use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Form\RedundantEditableConfigNamesTrait; + +/** + * Configure layout builder settings for this site. + * + * @internal + */ +final class LayoutBuilderSettingsForm extends ConfigFormBase { + + use RedundantEditableConfigNamesTrait; + + /** + * {@inheritdoc} + */ + public function getFormId(): string { + return 'layout_builder_settings'; + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, FormStateInterface $form_state): array { + $form['expose_all_field_blocks'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Expose all fields as blocks to layout builder'), + '#description' => $this->t('When enabled, this setting exposes all fields for all entity view displays.<br/> When disabled, only entity type bundles that have layout builder enabled will have their fields exposed.<br/> Enabling this setting could <strong>significantly decrease performance</strong> on sites with a large number of entity types and bundles.'), + '#config_target' => 'layout_builder.settings:expose_all_field_blocks', + ]; + return parent::buildForm($form, $form_state); + } + +} diff --git a/core/modules/layout_builder/src/Plugin/Derivative/ExtraFieldBlockDeriver.php b/core/modules/layout_builder/src/Plugin/Derivative/ExtraFieldBlockDeriver.php index 8de394c34953be996802a544eb060a1139e4a6fa..969d1ec8edc68f136e7302432825e2fe6ee4213f 100644 --- a/core/modules/layout_builder/src/Plugin/Derivative/ExtraFieldBlockDeriver.php +++ b/core/modules/layout_builder/src/Plugin/Derivative/ExtraFieldBlockDeriver.php @@ -4,6 +4,7 @@ use Drupal\Component\Plugin\Derivative\DeriverBase; use Drupal\Component\Plugin\PluginBase; +use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Entity\EntityFieldManagerInterface; use Drupal\Core\Entity\EntityTypeBundleInfoInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; @@ -63,8 +64,16 @@ class ExtraFieldBlockDeriver extends DeriverBase implements ContainerDeriverInte * The entity type bundle info. * @param \Drupal\Core\Entity\EntityTypeRepositoryInterface $entity_type_repository * The entity type repository. + * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory + * The config factory. */ - public function __construct(EntityFieldManagerInterface $entity_field_manager, EntityTypeManagerInterface $entity_type_manager, EntityTypeBundleInfoInterface $entity_type_bundle_info, EntityTypeRepositoryInterface $entity_type_repository) { + public function __construct( + EntityFieldManagerInterface $entity_field_manager, + EntityTypeManagerInterface $entity_type_manager, + EntityTypeBundleInfoInterface $entity_type_bundle_info, + EntityTypeRepositoryInterface $entity_type_repository, + protected ConfigFactoryInterface $configFactory, + ) { $this->entityFieldManager = $entity_field_manager; $this->entityTypeManager = $entity_type_manager; $this->entityTypeBundleInfo = $entity_type_bundle_info; @@ -79,7 +88,8 @@ public static function create(ContainerInterface $container, $base_plugin_id) { $container->get('entity_field.manager'), $container->get('entity_type.manager'), $container->get('entity_type.bundle.info'), - $container->get('entity_type.repository') + $container->get('entity_type.repository'), + $container->get('config.factory') ); } @@ -88,14 +98,26 @@ public static function create(ContainerInterface $container, $base_plugin_id) { */ public function getDerivativeDefinitions($base_plugin_definition) { $entity_type_labels = $this->entityTypeRepository->getEntityTypeLabels(); + $enabled_bundle_ids = $this->bundleIdsWithLayoutBuilderDisplays(); + $expose_all_fields = $this->configFactory->get('layout_builder.settings')->get('expose_all_field_blocks'); foreach ($this->entityTypeManager->getDefinitions() as $entity_type_id => $entity_type) { // Only process fieldable entity types. if (!$entity_type->entityClassImplements(FieldableEntityInterface::class)) { continue; } + // If not loading everything, skip entity types that aren't included. + if (!$expose_all_fields && !isset($enabled_bundle_ids[$entity_type_id])) { + continue; + } + $bundles = $this->entityTypeBundleInfo->getBundleInfo($entity_type_id); foreach ($bundles as $bundle_id => $bundle) { + // If not loading everything, skip bundle types that aren't included. + if (!$expose_all_fields && !isset($enabled_bundle_ids[$entity_type_id][$bundle_id])) { + continue; + } + $extra_fields = $this->entityFieldManager->getExtraFields($entity_type_id, $bundle_id); // Skip bundles without any extra fields. if (empty($extra_fields['display'])) { @@ -123,4 +145,23 @@ public function getDerivativeDefinitions($base_plugin_definition) { return $this->derivatives; } + /** + * Gets a list of entity type and bundle tuples that have layout builder enabled. + * + * @return array + * A structured array with entity type as first key, bundle as second. + */ + protected function bundleIdsWithLayoutBuilderDisplays(): array { + /** @var \Drupal\layout_builder\Entity\LayoutEntityDisplayInterface[] $displays */ + $displays = $this->entityTypeManager->getStorage('entity_view_display')->loadByProperties([ + 'third_party_settings.layout_builder.enabled' => TRUE, + ]); + $layout_bundles = []; + foreach ($displays as $display) { + $bundle = $display->getTargetBundle(); + $layout_bundles[$display->getTargetEntityTypeId()][$bundle] = $bundle; + } + return $layout_bundles; + } + } diff --git a/core/modules/layout_builder/src/Plugin/Derivative/FieldBlockDeriver.php b/core/modules/layout_builder/src/Plugin/Derivative/FieldBlockDeriver.php index 9dc935d70107da023d1cd3f02580085d1d22fd3c..44409b27b2e4256484dc6a8a04e625b3eaa8ce49 100644 --- a/core/modules/layout_builder/src/Plugin/Derivative/FieldBlockDeriver.php +++ b/core/modules/layout_builder/src/Plugin/Derivative/FieldBlockDeriver.php @@ -4,6 +4,8 @@ use Drupal\Component\Plugin\Derivative\DeriverBase; use Drupal\Component\Plugin\PluginBase; +use Drupal\Core\Config\ConfigFactoryInterface; +use Drupal\Core\Config\Entity\ConfigEntityStorageInterface; use Drupal\Core\Entity\EntityFieldManagerInterface; use Drupal\Core\Entity\EntityTypeRepositoryInterface; use Drupal\Core\Field\FieldConfigInterface; @@ -66,8 +68,19 @@ class FieldBlockDeriver extends DeriverBase implements ContainerDeriverInterface * The field type manager. * @param \Drupal\Core\Field\FormatterPluginManager $formatter_manager * The formatter manager. + * @param \Drupal\Core\Config\Entity\ConfigEntityStorageInterface $entityViewDisplayStorage + * The entity view display storage. + * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory + * The config factory. */ - public function __construct(EntityTypeRepositoryInterface $entity_type_repository, EntityFieldManagerInterface $entity_field_manager, FieldTypePluginManagerInterface $field_type_manager, FormatterPluginManager $formatter_manager) { + public function __construct( + EntityTypeRepositoryInterface $entity_type_repository, + EntityFieldManagerInterface $entity_field_manager, + FieldTypePluginManagerInterface $field_type_manager, + FormatterPluginManager $formatter_manager, + protected ConfigEntityStorageInterface $entityViewDisplayStorage, + protected ConfigFactoryInterface $configFactory, + ) { $this->entityTypeRepository = $entity_type_repository; $this->entityFieldManager = $entity_field_manager; $this->fieldTypeManager = $field_type_manager; @@ -82,7 +95,9 @@ public static function create(ContainerInterface $container, $base_plugin_id) { $container->get('entity_type.repository'), $container->get('entity_field.manager'), $container->get('plugin.manager.field.field_type'), - $container->get('plugin.manager.field.formatter') + $container->get('plugin.manager.field.formatter'), + $container->get('entity_type.manager')->getStorage('entity_view_display'), + $container->get('config.factory') ); } @@ -91,7 +106,7 @@ public static function create(ContainerInterface $container, $base_plugin_id) { */ public function getDerivativeDefinitions($base_plugin_definition) { $entity_type_labels = $this->entityTypeRepository->getEntityTypeLabels(); - foreach ($this->entityFieldManager->getFieldMap() as $entity_type_id => $entity_field_map) { + foreach ($this->getFieldMap() as $entity_type_id => $entity_field_map) { foreach ($entity_field_map as $field_name => $field_info) { // Skip fields without any formatters. $options = $this->formatterManager->getOptions($field_info['type']); @@ -142,4 +157,50 @@ public function getDerivativeDefinitions($base_plugin_definition) { return $this->derivatives; } + /** + * Returns the entity field map for deriving block definitions. + * + * @return array + * The entity field map. + * + * @see \Drupal\Core\Entity\EntityFieldManagerInterface::getFieldMap() + */ + protected function getFieldMap(): array { + $field_map = $this->entityFieldManager->getFieldMap(); + + // If all fields are exposed as field blocks, just return the field map + // without any further processing. + if ($this->configFactory->get('layout_builder.settings')->get('expose_all_field_blocks')) { + return $field_map; + } + + // Load all entity view displays which are using Layout Builder. + /** @var \Drupal\layout_builder\Entity\LayoutEntityDisplayInterface[] $displays */ + $displays = $this->entityViewDisplayStorage->loadByProperties([ + 'third_party_settings.layout_builder.enabled' => TRUE, + ]); + $layout_bundles = []; + foreach ($displays as $display) { + $bundle = $display->getTargetBundle(); + $layout_bundles[$display->getTargetEntityTypeId()][$bundle] = $bundle; + } + + // Process $field_map, removing any entity types which are not using Layout + // Builder. + $field_map = array_intersect_key($field_map, $layout_bundles); + + foreach ($field_map as $entity_type_id => $fields) { + foreach ($fields as $field_name => $field_info) { + $field_map[$entity_type_id][$field_name]['bundles'] = array_intersect($field_info['bundles'], $layout_bundles[$entity_type_id]); + + // If no bundles are using Layout Builder, remove this field from the + // field map. + if (empty($field_info['bundles'])) { + unset($field_map[$entity_type_id][$field_name]); + } + } + } + return $field_map; + } + } diff --git a/core/modules/layout_builder/tests/src/Functional/SettingsFormTest.php b/core/modules/layout_builder/tests/src/Functional/SettingsFormTest.php new file mode 100644 index 0000000000000000000000000000000000000000..884d63ede33970cc03606ff59aa02aaba1ec3476 --- /dev/null +++ b/core/modules/layout_builder/tests/src/Functional/SettingsFormTest.php @@ -0,0 +1,52 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\Tests\layout_builder\Functional; + +use Drupal\Core\Url; +use Drupal\Tests\BrowserTestBase; + +/** + * Tests the Layout Builder settings form. + * + * @coversDefaultClass \Drupal\layout_builder\Form\LayoutBuilderSettingsForm + * @group layout_builder + */ +class SettingsFormTest extends BrowserTestBase { + + /** + * {@inheritdoc} + */ + protected static $modules = ['layout_builder']; + + /** + * {@inheritdoc} + */ + protected $defaultTheme = 'stark'; + + /** + * Tests the Layout Builder settings form. + */ + public function testSettingsForm(): void { + $this->drupalLogin($this->drupalCreateUser([ + 'access administration pages', + 'administer layout builder', + ])); + + $this->drupalGet(Url::fromRoute('layout_builder.settings')); + $this->assertSession()->statusCodeEquals(200); + $this->submitForm([ + 'expose_all_field_blocks' => 1, + ], 'Save configuration'); + + $this->assertSession()->pageTextContains('The configuration options have been saved'); + $this->assertSession()->checkboxChecked('expose_all_field_blocks'); + $this->submitForm([ + 'expose_all_field_blocks' => 0, + ], 'Save configuration'); + $this->assertSession()->pageTextContains('The configuration options have been saved'); + $this->assertSession()->checkboxNotChecked('expose_all_field_blocks'); + } + +} diff --git a/core/modules/layout_builder/tests/src/Functional/Update/LayoutBuilderSettingsUpdateTest.php b/core/modules/layout_builder/tests/src/Functional/Update/LayoutBuilderSettingsUpdateTest.php new file mode 100644 index 0000000000000000000000000000000000000000..33c4fae7fb2c42040eedc90d89da20d0d161fbd3 --- /dev/null +++ b/core/modules/layout_builder/tests/src/Functional/Update/LayoutBuilderSettingsUpdateTest.php @@ -0,0 +1,44 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\Tests\layout_builder\Functional\Update; + +use Drupal\FunctionalTests\Update\UpdatePathTestBase; + +/** + * Tests creation of layout_builder settings. + * + * @see layout_builder_post_update_default_expose_field_block_setting() + * + * @group Update + */ +class LayoutBuilderSettingsUpdateTest extends UpdatePathTestBase { + + /** + * {@inheritdoc} + */ + protected function setDatabaseDumpFiles() { + $this->databaseDumpFiles = [ + __DIR__ . '/../../../../../system/tests/fixtures/update/drupal-9.4.0.bare.standard.php.gz', + __DIR__ . '/../../../fixtures/update/layout-builder.php', + ]; + } + + /** + * Tests layout_builder_post_update_default_expose_field_block_setting(). + */ + public function testLayoutBuilderPostUpdateExposeFieldBlockSetting(): void { + // Ensure config is not present. + $config = $this->config('layout_builder.settings'); + $this->assertTrue($config->isNew()); + + $this->runUpdates(); + + // Ensure config is present and setting is enabled. + $updated_config = $this->config('layout_builder.settings'); + $this->assertFalse($updated_config->isNew()); + $this->assertTrue($updated_config->get('expose_all_field_blocks')); + } + +} diff --git a/core/modules/layout_builder/tests/src/FunctionalJavascript/BlockFilterTest.php b/core/modules/layout_builder/tests/src/FunctionalJavascript/BlockFilterTest.php index fb7f50ae38e839659497970b7512e60d4f424e56..fa2a79d2f7dabc6416c961b9e80e45abd9b7a5ae 100644 --- a/core/modules/layout_builder/tests/src/FunctionalJavascript/BlockFilterTest.php +++ b/core/modules/layout_builder/tests/src/FunctionalJavascript/BlockFilterTest.php @@ -37,6 +37,12 @@ class BlockFilterTest extends WebDriverTestBase { protected function setUp(): void { parent::setUp(); + // This test makes assertions on lists of blocks, this includes a derived + // block from the user entity. + \Drupal::configFactory()->getEditable('layout_builder.settings') + ->set('expose_all_field_blocks', TRUE) + ->save(); + $this->drupalLogin($this->drupalCreateUser([ 'configure any layout', ])); diff --git a/core/modules/layout_builder/tests/src/FunctionalJavascript/FieldBlockTest.php b/core/modules/layout_builder/tests/src/FunctionalJavascript/FieldBlockTest.php index 9928c0554a7ccebadb235c7e3200ca9856c34549..b3847ab67008bc4a1a7e3e4d19d6490e81958341 100644 --- a/core/modules/layout_builder/tests/src/FunctionalJavascript/FieldBlockTest.php +++ b/core/modules/layout_builder/tests/src/FunctionalJavascript/FieldBlockTest.php @@ -40,6 +40,9 @@ class FieldBlockTest extends WebDriverTestBase { protected function setUp(): void { parent::setUp(); + \Drupal::configFactory()->getEditable('layout_builder.settings') + ->set('expose_all_field_blocks', TRUE) + ->save(); $field_storage = FieldStorageConfig::create([ 'field_name' => 'field_date', 'entity_type' => 'user', diff --git a/core/modules/layout_builder/tests/src/Kernel/FieldBlockDeriverTest.php b/core/modules/layout_builder/tests/src/Kernel/FieldBlockDeriverTest.php new file mode 100644 index 0000000000000000000000000000000000000000..21f68e01a6c8335823c0f5710cd4319218e63469 --- /dev/null +++ b/core/modules/layout_builder/tests/src/Kernel/FieldBlockDeriverTest.php @@ -0,0 +1,78 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\Tests\layout_builder\Kernel; + +use Drupal\KernelTests\Core\Entity\EntityKernelTestBase; +use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay; + +/** + * Tests field block plugin derivatives. + * + * @group layout_builder + */ +class FieldBlockDeriverTest extends EntityKernelTestBase { + + /** + * {@inheritdoc} + */ + protected static $modules = [ + 'layout_builder', + 'layout_discovery', + ]; + + /** + * Tests that field block derivers respect expose_all_field_blocks config. + * + * When expose_all_field_blocks is disabled (the default setting), only + * bundles that have layout builder enabled will expose their fields as + * field blocks. + */ + public function testFieldBlockDerivers(): void { + $plugins = $this->getBlockPluginIds(); + // Setting is disabled and entity_test bundles do not have layout builder + // configured. + $this->assertNotContains('field_block:user:user:name', $plugins); + $this->assertNotContains('extra_field_block:user:user:member_for', $plugins); + $this->assertNotContains('field_block:entity_test:entity_test:id', $plugins); + + // Enabling layout builder for entity_test adds field blocks for entity_test + // bundles, but not for the user entity type. + $display = LayoutBuilderEntityViewDisplay::create([ + 'targetEntityType' => 'entity_test', + 'bundle' => 'entity_test', + 'mode' => 'default', + 'status' => TRUE, + 'third_party_settings' => [ + 'layout_builder' => [ + 'enabled' => TRUE, + ], + ], + ]); + $display->save(); + $plugins = $this->getBlockPluginIds(); + $this->assertContains('field_block:entity_test:entity_test:id', $plugins); + $this->assertNotContains('field_block:user:user:name', $plugins); + $this->assertNotContains('extra_field_block:user:user:member_for', $plugins); + + // Exposing all field blocks adds them for the user entity type. + \Drupal::configFactory()->getEditable('layout_builder.settings') + ->set('expose_all_field_blocks', TRUE) + ->save(); + $plugins = $this->getBlockPluginIds(); + $this->assertContains('field_block:user:user:name', $plugins); + $this->assertContains('extra_field_block:user:user:member_for', $plugins); + } + + /** + * Get an uncached list of block plugin IDs. + * + * @return array + * A list of block plugin IDs. + */ + private function getBlockPluginIds(): array { + return \array_keys(\Drupal::service('plugin.manager.block')->getDefinitions()); + } + +}