diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php index 033cb5f178186830dad3d8e15c8bbe3d1112323c..5569dd09893dc69be9d4dba5c239157eab5a055e 100644 --- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php @@ -256,8 +256,8 @@ public function save(EntityInterface $entity) { // @see \Drupal\Core\Config\Entity\ConfigEntityStorage::MAX_ID_LENGTH // @todo Consider moving this to a protected method on the parent class, and // abstracting it for all entity types. - if (strlen($entity->get($this->idKey)) > self::MAX_ID_LENGTH) { - throw new ConfigEntityIdLengthException("Configuration entity ID {$entity->get($this->idKey)} exceeds maximum allowed length of " . self::MAX_ID_LENGTH . " characters."); + if (strlen($entity->get($this->idKey)) > static::MAX_ID_LENGTH) { + throw new ConfigEntityIdLengthException("Configuration entity ID {$entity->get($this->idKey)} exceeds maximum allowed length of " . static::MAX_ID_LENGTH . " characters."); } return parent::save($entity); diff --git a/core/modules/menu_ui/menu_ui.module b/core/modules/menu_ui/menu_ui.module index d804ae6ceaa17d31ffef394673fc72482232ce6f..17320f500b25ce196be0f5e4cbeb80011b9574d0 100644 --- a/core/modules/menu_ui/menu_ui.module +++ b/core/modules/menu_ui/menu_ui.module @@ -25,10 +25,10 @@ * Maximum length of menu name as entered by the user. * * @deprecated in drupal:8.3.0 and is removed from drupal:9.0.0. Use - * \Drupal\Core\Config\Entity\ConfigEntityStorage::MAX_ID_LENGTH because the - * menu name is a configuration entity ID. + * \Drupal\system\MenuStorage::MAX_ID_LENGTH instead. * * @see https://www.drupal.org/node/2831620 + * @see \Drupal\system\MenuStorage::MAX_ID_LENGTH */ const MENU_MAX_MENU_NAME_LENGTH_UI = 27; diff --git a/core/modules/menu_ui/src/MenuForm.php b/core/modules/menu_ui/src/MenuForm.php index ccedad3133eb2b2b693c68e1d9388dad13a14e84..5a2044e8a07d4c239a354c8b70add2f6d419cd8e 100644 --- a/core/modules/menu_ui/src/MenuForm.php +++ b/core/modules/menu_ui/src/MenuForm.php @@ -17,6 +17,7 @@ use Drupal\Core\Utility\LinkGeneratorInterface; use Drupal\menu_link_content\MenuLinkContentStorageInterface; use Drupal\menu_link_content\Plugin\Menu\MenuLinkContent; +use Drupal\system\MenuStorage; use Symfony\Component\DependencyInjection\ContainerInterface; /** @@ -112,7 +113,7 @@ public function form(array $form, FormStateInterface $form_state) { '#type' => 'machine_name', '#title' => $this->t('Menu name'), '#default_value' => $menu->id(), - '#maxlength' => MENU_MAX_MENU_NAME_LENGTH_UI, + '#maxlength' => MenuStorage::MAX_ID_LENGTH, '#description' => $this->t('A unique name to construct the URL for the menu. It must only contain lowercase letters, numbers and hyphens.'), '#machine_name' => [ 'exists' => [$this, 'menuNameExists'], diff --git a/core/modules/menu_ui/tests/src/Functional/MenuUiTest.php b/core/modules/menu_ui/tests/src/Functional/MenuUiTest.php index d04075d004b6f4886ea7adb6c2171317d28e65a9..63626bbf43d051cfaeba643776f203af98571ce7 100644 --- a/core/modules/menu_ui/tests/src/Functional/MenuUiTest.php +++ b/core/modules/menu_ui/tests/src/Functional/MenuUiTest.php @@ -10,6 +10,7 @@ use Drupal\system\Entity\Menu; use Drupal\node\Entity\Node; use Drupal\node\NodeInterface; +use Drupal\system\MenuStorage; use Drupal\Tests\BrowserTestBase; use Drupal\Tests\menu_ui\Traits\MenuUiTrait; @@ -167,7 +168,7 @@ public function testMenu() { */ public function addCustomMenuCRUD() { // Add a new custom menu. - $menu_name = substr(hash('sha256', $this->randomMachineName(16)), 0, MENU_MAX_MENU_NAME_LENGTH_UI); + $menu_name = strtolower($this->randomMachineName(MenuStorage::MAX_ID_LENGTH)); $label = $this->randomMachineName(16); $menu = Menu::create([ @@ -198,7 +199,7 @@ public function addCustomMenuCRUD() { public function addCustomMenu() { // Try adding a menu using a menu_name that is too long. $this->drupalGet('admin/structure/menu/add'); - $menu_name = substr(hash('sha256', $this->randomMachineName(16)), 0, MENU_MAX_MENU_NAME_LENGTH_UI + 1); + $menu_name = strtolower($this->randomMachineName(MenuStorage::MAX_ID_LENGTH + 1)); $label = $this->randomMachineName(16); $edit = [ 'id' => $menu_name, @@ -211,19 +212,19 @@ public function addCustomMenu() { // message. $this->assertRaw(t('@name cannot be longer than %max characters but is currently %length characters long.', [ '@name' => t('Menu name'), - '%max' => MENU_MAX_MENU_NAME_LENGTH_UI, + '%max' => MenuStorage::MAX_ID_LENGTH, '%length' => mb_strlen($menu_name), ])); // Change the menu_name so it no longer exceeds the maximum length. - $menu_name = substr(hash('sha256', $this->randomMachineName(16)), 0, MENU_MAX_MENU_NAME_LENGTH_UI); + $menu_name = strtolower($this->randomMachineName(MenuStorage::MAX_ID_LENGTH)); $edit['id'] = $menu_name; $this->drupalPostForm('admin/structure/menu/add', $edit, t('Save')); // Verify that no validation error is given for menu_name length. $this->assertNoRaw(t('@name cannot be longer than %max characters but is currently %length characters long.', [ '@name' => t('Menu name'), - '%max' => MENU_MAX_MENU_NAME_LENGTH_UI, + '%max' => MenuStorage::MAX_ID_LENGTH, '%length' => mb_strlen($menu_name), ])); // Verify that the confirmation message is displayed. diff --git a/core/modules/menu_ui/tests/src/FunctionalJavascript/MenuUiJavascriptTest.php b/core/modules/menu_ui/tests/src/FunctionalJavascript/MenuUiJavascriptTest.php index fea04e60bddf0503d80adeef22d955ccf9e1abe5..f9f9e8c406ea6ca0f70cb5e13fa22d912a352bf9 100644 --- a/core/modules/menu_ui/tests/src/FunctionalJavascript/MenuUiJavascriptTest.php +++ b/core/modules/menu_ui/tests/src/FunctionalJavascript/MenuUiJavascriptTest.php @@ -4,6 +4,7 @@ use Drupal\FunctionalJavascriptTests\WebDriverTestBase; use Drupal\system\Entity\Menu; +use Drupal\system\MenuStorage; use Drupal\Tests\contextual\FunctionalJavascript\ContextualLinkClickTrait; use Drupal\Tests\menu_ui\Traits\MenuUiTrait; @@ -74,7 +75,7 @@ public function testBlockContextualLinks() { protected function addCustomMenu() { // Try adding a menu using a menu_name that is too long. $label = $this->randomMachineName(16); - $menu_id = strtolower($this->randomMachineName(MENU_MAX_MENU_NAME_LENGTH_UI + 1)); + $menu_id = strtolower($this->randomMachineName(MenuStorage::MAX_ID_LENGTH + 1)); $this->drupalGet('admin/structure/menu/add'); $page = $this->getSession()->getPage(); @@ -88,7 +89,7 @@ protected function addCustomMenu() { $page->fillField('Menu name', $menu_id); $page->pressButton('Save'); // Check that the menu was saved with the ID truncated to the max length. - $menu = Menu::load(substr($menu_id, 0, MENU_MAX_MENU_NAME_LENGTH_UI)); + $menu = Menu::load(substr($menu_id, 0, MenuStorage::MAX_ID_LENGTH)); $this->assertEquals($label, $menu->label()); // Check that the menu was added. diff --git a/core/modules/system/src/Entity/Menu.php b/core/modules/system/src/Entity/Menu.php index 14830099e0a2562f5f55408e0d04f8de9b07c456..546aa34a86e93032ed1945a66c5a8b37a7f3764f 100644 --- a/core/modules/system/src/Entity/Menu.php +++ b/core/modules/system/src/Entity/Menu.php @@ -20,7 +20,8 @@ * plural = "@count menus", * ), * handlers = { - * "access" = "Drupal\system\MenuAccessControlHandler" + * "access" = "Drupal\system\MenuAccessControlHandler", + * "storage" = "Drupal\system\MenuStorage", * }, * admin_permission = "administer menu", * entity_keys = { diff --git a/core/modules/system/src/MenuStorage.php b/core/modules/system/src/MenuStorage.php new file mode 100644 index 0000000000000000000000000000000000000000..0d9d9560f6a83da46291c0467a30c61358565f8b --- /dev/null +++ b/core/modules/system/src/MenuStorage.php @@ -0,0 +1,25 @@ +<?php + +namespace Drupal\system; + +use Drupal\Core\Config\Entity\ConfigEntityStorage; + +/** + * Defines the storage class for menu configuration entities. + */ +class MenuStorage extends ConfigEntityStorage { + + /** + * Menu names have a maximum length of 32. + * + * This is based on: + * - menu_tree table schema definition, + * - \Drupal\Core\Config\Entity\ConfigEntityStorage::MAX_ID_LENGTH + * - menu_name base field on the Menu Link content entity. + * + * @see \Drupal\Core\Menu\MenuTreeStorage::schemaDefinition() + * @see \Drupal\menu_link_content\Entity\MenuLinkContent::baseFieldDefinitions() + */ + const MAX_ID_LENGTH = 32; + +} diff --git a/core/modules/system/tests/src/Kernel/Menu/MenuStorageTest.php b/core/modules/system/tests/src/Kernel/Menu/MenuStorageTest.php new file mode 100644 index 0000000000000000000000000000000000000000..bec077f40acfe6fece66edf7c912b3ae8a41ed29 --- /dev/null +++ b/core/modules/system/tests/src/Kernel/Menu/MenuStorageTest.php @@ -0,0 +1,36 @@ +<?php + +namespace Drupal\Tests\system\Kernel\Menu; + +use Drupal\Core\Config\Entity\Exception\ConfigEntityIdLengthException; +use Drupal\KernelTests\KernelTestBase; +use Drupal\system\Entity\Menu; +use Drupal\system\MenuStorage; + +/** + * Tests MenuStorage. + * + * @group Menu + * + * @see \Drupal\system\MenuStorage + */ +class MenuStorageTest extends KernelTestBase { + + /** + * {@inheritdoc} + */ + protected static $modules = ['system']; + + /** + * Tests MenuStorage::MAX_ID_LENGTH is enforced. + */ + public function testMaxIdLengthException() { + $id = $this->randomMachineName(MenuStorage::MAX_ID_LENGTH + 1); + $this->expectException(ConfigEntityIdLengthException::class); + $this->expectExceptionMessage( + sprintf('Configuration entity ID %s exceeds maximum allowed length of %s characters.', $id, MenuStorage::MAX_ID_LENGTH) + ); + Menu::create(['id' => $id])->save(); + } + +}