Loading core/modules/block/block.module +3 −2 Changes for core/modules/block/block.module: 3 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -128,11 +128,12 @@ function block_theme_initialize($theme) { $default_theme_blocks = \Drupal::entityTypeManager()->getStorage('block')->loadByProperties(['theme' => $default_theme]); foreach ($default_theme_blocks as $default_theme_block_id => $default_theme_block) { if (str_starts_with($default_theme_block_id, $default_theme . '_')) { $id = str_replace($default_theme, $theme, $default_theme_block_id); $id = str_replace($default_theme . '_', '', $default_theme_block_id); } else { $id = $theme . '_' . $default_theme_block_id; $id = $default_theme_block_id; } $id = \Drupal::service('block.repository')->getUniqueMachineName($id, $theme); $block = $default_theme_block->createDuplicateBlock($id, $theme); // If the region isn't supported by the theme, assign the block to the // theme's default region. Loading core/modules/block/src/BlockForm.php +19 −25 Changes for core/modules/block/src/BlockForm.php: 19 added lines, 25 removed lines. Original line number Diff line number Diff line Loading @@ -73,6 +73,13 @@ class BlockForm extends EntityForm { */ protected $pluginFormFactory; /** * The block repository service. * * @var \Drupal\block\BlockRepositoryInterface */ protected $blockRepository; /** * Constructs a BlockForm object. * Loading @@ -88,14 +95,21 @@ class BlockForm extends EntityForm { * The theme handler. * @param \Drupal\Core\Plugin\PluginFormFactoryInterface $plugin_form_manager * The plugin form manager. * @param \Drupal\block\BlockRepositoryInterface|null $block_repository * The block repository service. */ public function __construct(EntityTypeManagerInterface $entity_type_manager, ExecutableManagerInterface $manager, ContextRepositoryInterface $context_repository, LanguageManagerInterface $language, ThemeHandlerInterface $theme_handler, PluginFormFactoryInterface $plugin_form_manager) { public function __construct(EntityTypeManagerInterface $entity_type_manager, ExecutableManagerInterface $manager, ContextRepositoryInterface $context_repository, LanguageManagerInterface $language, ThemeHandlerInterface $theme_handler, PluginFormFactoryInterface $plugin_form_manager, ?BlockRepositoryInterface $block_repository = NULL) { if ($block_repository === NULL) { @trigger_error('Calling ' . __METHOD__ . ' without the $block_repository argument is deprecated in drupal:10.2.0 and will be required in drupal:11.0.0. See https://www.drupal.org/node/3333575', E_USER_DEPRECATED); $block_repository = \Drupal::service('block.repository'); } $this->storage = $entity_type_manager->getStorage('block'); $this->manager = $manager; $this->contextRepository = $context_repository; $this->language = $language; $this->themeHandler = $theme_handler; $this->pluginFormFactory = $plugin_form_manager; $this->blockRepository = $block_repository; } /** Loading @@ -108,7 +122,8 @@ public static function create(ContainerInterface $container) { $container->get('context.repository'), $container->get('language_manager'), $container->get('theme_handler'), $container->get('plugin_form.factory') $container->get('plugin_form.factory'), $container->get('block.repository') ); } Loading Loading @@ -380,7 +395,7 @@ protected function submitVisibility(array $form, FormStateInterface $form_state) } /** * Generates a unique machine name for a block. * Generates a unique machine name for a block based on a suggested string. * * @param \Drupal\block\BlockInterface $block * The block entity. Loading @@ -390,28 +405,7 @@ protected function submitVisibility(array $form, FormStateInterface $form_state) */ public function getUniqueMachineName(BlockInterface $block) { $suggestion = $block->getPlugin()->getMachineNameSuggestion(); if ($block->getTheme()) { $suggestion = $block->getTheme() . '_' . $suggestion; } // Get all the blocks which starts with the suggested machine name. $query = $this->storage->getQuery(); $query->condition('id', $suggestion, 'CONTAINS'); $block_ids = $query->execute(); $block_ids = array_map(function ($block_id) { $parts = explode('.', $block_id); return end($parts); }, $block_ids); // Iterate through potential IDs until we get a new one. E.g. // 'plugin', 'plugin_2', 'plugin_3', etc. $count = 1; $machine_default = $suggestion; while (in_array($machine_default, $block_ids)) { $machine_default = $suggestion . '_' . ++$count; } return $machine_default; return $this->blockRepository->getUniqueMachineName($suggestion, $block->getTheme()); } /** Loading core/modules/block/src/BlockRepository.php +28 −0 Changes for core/modules/block/src/BlockRepository.php: 28 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -83,4 +83,32 @@ public function getVisibleBlocksPerRegion(array &$cacheable_metadata = []) { return $assignments; } /** * {@inheritdoc} */ public function getUniqueMachineName(string $suggestion, string $theme = NULL): string { if ($theme) { $suggestion = $theme . '_' . $suggestion; } // Get all the block machine names that begin with the suggested string. $query = $this->blockStorage->getQuery(); $query->accessCheck(FALSE); $query->condition('id', $suggestion, 'CONTAINS'); $block_ids = $query->execute(); $block_ids = array_map(function ($block_id) { $parts = explode('.', $block_id); return end($parts); }, $block_ids); // Iterate through potential IDs until we get a new one. E.g. // For example, 'plugin', 'plugin_2', 'plugin_3', etc. $count = 1; $machine_default = $suggestion; while (in_array($machine_default, $block_ids)) { $machine_default = $suggestion . '_' . ++$count; } return $machine_default; } } core/modules/block/src/BlockRepositoryInterface.php +13 −0 Changes for core/modules/block/src/BlockRepositoryInterface.php: 13 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -31,4 +31,17 @@ interface BlockRepositoryInterface { */ public function getVisibleBlocksPerRegion(array &$cacheable_metadata = []); /** * Based on a suggested string generates a unique machine name for a block. * * @param string $suggestion * The suggested block ID. * @param string $theme * The machine name of the theme. * * @return string * Returns the unique name. */ public function getUniqueMachineName(string $suggestion, string $theme): string; } core/modules/block/tests/src/Kernel/NewDefaultThemeBlocksTest.php +98 −5 Changes for core/modules/block/tests/src/Kernel/NewDefaultThemeBlocksTest.php: 98 added lines, 5 removed lines. Original line number Diff line number Diff line Loading @@ -23,14 +23,36 @@ class NewDefaultThemeBlocksTest extends KernelTestBase { 'user', ]; /** * The theme installer service. * * @var \Drupal\Core\Extension\ThemeInstallerInterface */ protected $themeInstaller; /** * The default theme. */ protected $defaultTheme; /** * {@inheritdoc} */ protected function setUp(): void { parent::setUp(); $this->installConfig(['system']); /** @var \Drupal\Core\Extension\ThemeInstallerInterface $themeInstaller */ $this->themeInstaller = $this->container->get('theme_installer'); $this->defaultTheme = $this->config('system.theme')->get('default'); } /** * Check the blocks are correctly copied by block_themes_installed(). */ public function testNewDefaultThemeBlocks() { $this->installConfig(['system']); /** @var \Drupal\Core\Extension\ThemeInstallerInterface $theme_installer */ $theme_installer = $this->container->get('theme_installer'); $default_theme = $this->config('system.theme')->get('default'); $default_theme = $this->defaultTheme; $theme_installer = $this->themeInstaller; $theme_installer->install([$default_theme]); // Add two instances of the user login block. Loading Loading @@ -61,25 +83,96 @@ public function testNewDefaultThemeBlocks() { // Ensure that the new default theme has the same blocks as the previous // default theme. $default_block_names = $block_storage->getQuery() ->accessCheck(FALSE) ->condition('theme', $default_theme) ->execute(); $new_blocks = $block_storage->getQuery() ->accessCheck(FALSE) ->condition('theme', $new_theme) ->execute(); $this->assertSameSize($default_block_names, $new_blocks); foreach ($default_block_names as $default_block_name) { // Remove the matching block from the list of blocks in the new theme. // For example, if the old theme has block.block.stark_admin, // unset block.block.olivero_admin. unset($new_blocks[str_replace($default_theme . '_', $new_theme . '_', $default_block_name)]); } $this->assertEmpty($new_blocks); // Install a hidden base theme and ensure blocks are not copied. $base_theme = 'test_basetheme'; $theme_installer->install([$base_theme]); $new_blocks = $block_storage->getQuery() ->accessCheck(FALSE) ->condition('theme', $base_theme) ->execute(); $this->assertEmpty($new_blocks); } /** * Checks that a theme block is still created when same ID exists. */ public function testBlockCollision() { $default_theme = $this->defaultTheme; $theme_installer = $this->themeInstaller; $theme_installer->install([$default_theme]); // Add two instances of the user login block with machine // names that will collide. $this->placeBlock('user_login_block', [ 'id' => 'user_login_block', ]); $this->placeBlock('user_login_block', [ 'id' => $default_theme . '_user_login_block', ]); // Add an instance of a different block. $this->placeBlock('system_powered_by_block', [ 'id' => $default_theme . '_' . strtolower($this->randomMachineName(8)), ]); // Install a different theme that does not have blocks. $new_theme = 'test_theme'; // The new theme is different from the previous default theme. $this->assertNotEquals($new_theme, $default_theme); $theme_installer->install([$new_theme]); $this->config('system.theme') ->set('default', $new_theme) ->save(); $block_storage = $this->container->get('entity_type.manager')->getStorage('block'); // Ensure that the new default theme has the same blocks as the previous // default theme. $default_block_names = $block_storage->getQuery() ->accessCheck(FALSE) ->condition('theme', $default_theme) ->execute(); $new_blocks = $block_storage->getQuery() ->accessCheck(FALSE) ->condition('theme', $new_theme) ->execute(); $this->assertSameSize($default_block_names, $new_blocks); foreach ($default_block_names as $default_block_name) { // Remove the matching block from the list of blocks in the new theme. // E.g., if the old theme has block.block.stark_admin, // For example, if the old theme has block.block.stark_admin, // unset block.block.olivero_admin. unset($new_blocks[str_replace($default_theme . '_', $new_theme . '_', $default_block_name)]); } // The test_theme_user_login_block machine name is already in use, so therefore // \Drupal\block\BlockRepository::getUniqueMachineName // appends a counter. unset($new_blocks[$new_theme . '_user_login_block_2']); $this->assertEmpty($new_blocks); // Install a hidden base theme and ensure blocks are not copied. $base_theme = 'test_basetheme'; $theme_installer->install([$base_theme]); $new_blocks = $block_storage->getQuery() ->accessCheck(FALSE) ->condition('theme', $base_theme) ->execute(); // Installing a hidden base theme does not copy the blocks from the default Loading Loading
core/modules/block/block.module +3 −2 Changes for core/modules/block/block.module: 3 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -128,11 +128,12 @@ function block_theme_initialize($theme) { $default_theme_blocks = \Drupal::entityTypeManager()->getStorage('block')->loadByProperties(['theme' => $default_theme]); foreach ($default_theme_blocks as $default_theme_block_id => $default_theme_block) { if (str_starts_with($default_theme_block_id, $default_theme . '_')) { $id = str_replace($default_theme, $theme, $default_theme_block_id); $id = str_replace($default_theme . '_', '', $default_theme_block_id); } else { $id = $theme . '_' . $default_theme_block_id; $id = $default_theme_block_id; } $id = \Drupal::service('block.repository')->getUniqueMachineName($id, $theme); $block = $default_theme_block->createDuplicateBlock($id, $theme); // If the region isn't supported by the theme, assign the block to the // theme's default region. Loading
core/modules/block/src/BlockForm.php +19 −25 Changes for core/modules/block/src/BlockForm.php: 19 added lines, 25 removed lines. Original line number Diff line number Diff line Loading @@ -73,6 +73,13 @@ class BlockForm extends EntityForm { */ protected $pluginFormFactory; /** * The block repository service. * * @var \Drupal\block\BlockRepositoryInterface */ protected $blockRepository; /** * Constructs a BlockForm object. * Loading @@ -88,14 +95,21 @@ class BlockForm extends EntityForm { * The theme handler. * @param \Drupal\Core\Plugin\PluginFormFactoryInterface $plugin_form_manager * The plugin form manager. * @param \Drupal\block\BlockRepositoryInterface|null $block_repository * The block repository service. */ public function __construct(EntityTypeManagerInterface $entity_type_manager, ExecutableManagerInterface $manager, ContextRepositoryInterface $context_repository, LanguageManagerInterface $language, ThemeHandlerInterface $theme_handler, PluginFormFactoryInterface $plugin_form_manager) { public function __construct(EntityTypeManagerInterface $entity_type_manager, ExecutableManagerInterface $manager, ContextRepositoryInterface $context_repository, LanguageManagerInterface $language, ThemeHandlerInterface $theme_handler, PluginFormFactoryInterface $plugin_form_manager, ?BlockRepositoryInterface $block_repository = NULL) { if ($block_repository === NULL) { @trigger_error('Calling ' . __METHOD__ . ' without the $block_repository argument is deprecated in drupal:10.2.0 and will be required in drupal:11.0.0. See https://www.drupal.org/node/3333575', E_USER_DEPRECATED); $block_repository = \Drupal::service('block.repository'); } $this->storage = $entity_type_manager->getStorage('block'); $this->manager = $manager; $this->contextRepository = $context_repository; $this->language = $language; $this->themeHandler = $theme_handler; $this->pluginFormFactory = $plugin_form_manager; $this->blockRepository = $block_repository; } /** Loading @@ -108,7 +122,8 @@ public static function create(ContainerInterface $container) { $container->get('context.repository'), $container->get('language_manager'), $container->get('theme_handler'), $container->get('plugin_form.factory') $container->get('plugin_form.factory'), $container->get('block.repository') ); } Loading Loading @@ -380,7 +395,7 @@ protected function submitVisibility(array $form, FormStateInterface $form_state) } /** * Generates a unique machine name for a block. * Generates a unique machine name for a block based on a suggested string. * * @param \Drupal\block\BlockInterface $block * The block entity. Loading @@ -390,28 +405,7 @@ protected function submitVisibility(array $form, FormStateInterface $form_state) */ public function getUniqueMachineName(BlockInterface $block) { $suggestion = $block->getPlugin()->getMachineNameSuggestion(); if ($block->getTheme()) { $suggestion = $block->getTheme() . '_' . $suggestion; } // Get all the blocks which starts with the suggested machine name. $query = $this->storage->getQuery(); $query->condition('id', $suggestion, 'CONTAINS'); $block_ids = $query->execute(); $block_ids = array_map(function ($block_id) { $parts = explode('.', $block_id); return end($parts); }, $block_ids); // Iterate through potential IDs until we get a new one. E.g. // 'plugin', 'plugin_2', 'plugin_3', etc. $count = 1; $machine_default = $suggestion; while (in_array($machine_default, $block_ids)) { $machine_default = $suggestion . '_' . ++$count; } return $machine_default; return $this->blockRepository->getUniqueMachineName($suggestion, $block->getTheme()); } /** Loading
core/modules/block/src/BlockRepository.php +28 −0 Changes for core/modules/block/src/BlockRepository.php: 28 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -83,4 +83,32 @@ public function getVisibleBlocksPerRegion(array &$cacheable_metadata = []) { return $assignments; } /** * {@inheritdoc} */ public function getUniqueMachineName(string $suggestion, string $theme = NULL): string { if ($theme) { $suggestion = $theme . '_' . $suggestion; } // Get all the block machine names that begin with the suggested string. $query = $this->blockStorage->getQuery(); $query->accessCheck(FALSE); $query->condition('id', $suggestion, 'CONTAINS'); $block_ids = $query->execute(); $block_ids = array_map(function ($block_id) { $parts = explode('.', $block_id); return end($parts); }, $block_ids); // Iterate through potential IDs until we get a new one. E.g. // For example, 'plugin', 'plugin_2', 'plugin_3', etc. $count = 1; $machine_default = $suggestion; while (in_array($machine_default, $block_ids)) { $machine_default = $suggestion . '_' . ++$count; } return $machine_default; } }
core/modules/block/src/BlockRepositoryInterface.php +13 −0 Changes for core/modules/block/src/BlockRepositoryInterface.php: 13 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -31,4 +31,17 @@ interface BlockRepositoryInterface { */ public function getVisibleBlocksPerRegion(array &$cacheable_metadata = []); /** * Based on a suggested string generates a unique machine name for a block. * * @param string $suggestion * The suggested block ID. * @param string $theme * The machine name of the theme. * * @return string * Returns the unique name. */ public function getUniqueMachineName(string $suggestion, string $theme): string; }
core/modules/block/tests/src/Kernel/NewDefaultThemeBlocksTest.php +98 −5 Changes for core/modules/block/tests/src/Kernel/NewDefaultThemeBlocksTest.php: 98 added lines, 5 removed lines. Original line number Diff line number Diff line Loading @@ -23,14 +23,36 @@ class NewDefaultThemeBlocksTest extends KernelTestBase { 'user', ]; /** * The theme installer service. * * @var \Drupal\Core\Extension\ThemeInstallerInterface */ protected $themeInstaller; /** * The default theme. */ protected $defaultTheme; /** * {@inheritdoc} */ protected function setUp(): void { parent::setUp(); $this->installConfig(['system']); /** @var \Drupal\Core\Extension\ThemeInstallerInterface $themeInstaller */ $this->themeInstaller = $this->container->get('theme_installer'); $this->defaultTheme = $this->config('system.theme')->get('default'); } /** * Check the blocks are correctly copied by block_themes_installed(). */ public function testNewDefaultThemeBlocks() { $this->installConfig(['system']); /** @var \Drupal\Core\Extension\ThemeInstallerInterface $theme_installer */ $theme_installer = $this->container->get('theme_installer'); $default_theme = $this->config('system.theme')->get('default'); $default_theme = $this->defaultTheme; $theme_installer = $this->themeInstaller; $theme_installer->install([$default_theme]); // Add two instances of the user login block. Loading Loading @@ -61,25 +83,96 @@ public function testNewDefaultThemeBlocks() { // Ensure that the new default theme has the same blocks as the previous // default theme. $default_block_names = $block_storage->getQuery() ->accessCheck(FALSE) ->condition('theme', $default_theme) ->execute(); $new_blocks = $block_storage->getQuery() ->accessCheck(FALSE) ->condition('theme', $new_theme) ->execute(); $this->assertSameSize($default_block_names, $new_blocks); foreach ($default_block_names as $default_block_name) { // Remove the matching block from the list of blocks in the new theme. // For example, if the old theme has block.block.stark_admin, // unset block.block.olivero_admin. unset($new_blocks[str_replace($default_theme . '_', $new_theme . '_', $default_block_name)]); } $this->assertEmpty($new_blocks); // Install a hidden base theme and ensure blocks are not copied. $base_theme = 'test_basetheme'; $theme_installer->install([$base_theme]); $new_blocks = $block_storage->getQuery() ->accessCheck(FALSE) ->condition('theme', $base_theme) ->execute(); $this->assertEmpty($new_blocks); } /** * Checks that a theme block is still created when same ID exists. */ public function testBlockCollision() { $default_theme = $this->defaultTheme; $theme_installer = $this->themeInstaller; $theme_installer->install([$default_theme]); // Add two instances of the user login block with machine // names that will collide. $this->placeBlock('user_login_block', [ 'id' => 'user_login_block', ]); $this->placeBlock('user_login_block', [ 'id' => $default_theme . '_user_login_block', ]); // Add an instance of a different block. $this->placeBlock('system_powered_by_block', [ 'id' => $default_theme . '_' . strtolower($this->randomMachineName(8)), ]); // Install a different theme that does not have blocks. $new_theme = 'test_theme'; // The new theme is different from the previous default theme. $this->assertNotEquals($new_theme, $default_theme); $theme_installer->install([$new_theme]); $this->config('system.theme') ->set('default', $new_theme) ->save(); $block_storage = $this->container->get('entity_type.manager')->getStorage('block'); // Ensure that the new default theme has the same blocks as the previous // default theme. $default_block_names = $block_storage->getQuery() ->accessCheck(FALSE) ->condition('theme', $default_theme) ->execute(); $new_blocks = $block_storage->getQuery() ->accessCheck(FALSE) ->condition('theme', $new_theme) ->execute(); $this->assertSameSize($default_block_names, $new_blocks); foreach ($default_block_names as $default_block_name) { // Remove the matching block from the list of blocks in the new theme. // E.g., if the old theme has block.block.stark_admin, // For example, if the old theme has block.block.stark_admin, // unset block.block.olivero_admin. unset($new_blocks[str_replace($default_theme . '_', $new_theme . '_', $default_block_name)]); } // The test_theme_user_login_block machine name is already in use, so therefore // \Drupal\block\BlockRepository::getUniqueMachineName // appends a counter. unset($new_blocks[$new_theme . '_user_login_block_2']); $this->assertEmpty($new_blocks); // Install a hidden base theme and ensure blocks are not copied. $base_theme = 'test_basetheme'; $theme_installer->install([$base_theme]); $new_blocks = $block_storage->getQuery() ->accessCheck(FALSE) ->condition('theme', $base_theme) ->execute(); // Installing a hidden base theme does not copy the blocks from the default Loading