diff --git a/core/core.services.yml b/core/core.services.yml index e74e688..786d1ed 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -1164,8 +1164,9 @@ services: - { name: route_processor_outbound, priority: 200 } route_processor_entity_uuid: class: Drupal\Core\RouteProcessor\RouteProcessorEntityUUID + arguments: ['@entity.manager'] tags: - - { name: route_processor_outbound, priority: } + - { name: route_processor_outbound, priority: 100 } path_processor_alias: class: Drupal\Core\PathProcessor\PathProcessorAlias tags: diff --git a/core/lib/Drupal/Core/Menu/DefaultMenuLinkTreeManipulators.php b/core/lib/Drupal/Core/Menu/DefaultMenuLinkTreeManipulators.php index 381baf3..2c7307d 100644 --- a/core/lib/Drupal/Core/Menu/DefaultMenuLinkTreeManipulators.php +++ b/core/lib/Drupal/Core/Menu/DefaultMenuLinkTreeManipulators.php @@ -140,9 +140,10 @@ public function checkNodeAccess(array $tree) { $nids = array_keys($node_links); $query = $this->queryFactory->get('node'); - $query->orConditionGroup() + $group = $query->orConditionGroup() ->condition('nid', $nids, 'IN') ->condition('uuid', $nids, 'IN'); + $query->condition($group); // Allows admins to view all nodes, by both disabling node_access // query rewrite as well as not checking for the node status. The @@ -158,9 +159,11 @@ public function checkNodeAccess(array $tree) { } $nids = $query->execute(); - foreach ($nids as $nid) { - foreach ($node_links[$nid] as $key => $link) { - $node_links[$nid][$key]->access = $access_result; + foreach ($node_links as $nid => $links) { + foreach ($links as $key => $link) { + if (isset($nids[$nid])) { + $node_links[$nid][$key]->access = $access_result; + } } } } @@ -181,8 +184,8 @@ public function checkNodeAccess(array $tree) { */ protected function collectNodeLinks(array &$tree, array &$node_links) { foreach ($tree as $key => &$element) { - if ($element->link->getRouteName() == 'entity.node.canonical') { - $nid = $element->link->getRouteParameters()['node']; + if (($url = $element->link->getUrlObject()) && !$url->isExternal() && $url->getRouteName() == 'entity.node.canonical') { + $nid = $element->link->getUrlObject()->getRouteParameters()['node']; $node_links[$nid][$key] = $element; // Deny access by default. checkNodeAccess() will re-add it. $element->access = AccessResult::neutral(); diff --git a/core/lib/Drupal/Core/RouteProcessor/RouteProcessorEntityUUID.php b/core/lib/Drupal/Core/RouteProcessor/RouteProcessorEntityUUID.php index 2fe8bf1..3c5ef78 100644 --- a/core/lib/Drupal/Core/RouteProcessor/RouteProcessorEntityUUID.php +++ b/core/lib/Drupal/Core/RouteProcessor/RouteProcessorEntityUUID.php @@ -8,6 +8,7 @@ namespace Drupal\Core\RouteProcessor; use Drupal\Core\Entity\EntityManagerInterface; +use Drupal\Core\Render\BubbleableMetadata; use Symfony\Component\Routing\Route; /** @@ -35,7 +36,7 @@ public function __construct(EntityManagerInterface $entity_manager) { /** * {@inheritdoc} */ - public function processOutbound($route_name, Route $route, array &$parameters) { + public function processOutbound($route_name, Route $route, array &$parameters, BubbleableMetadata $bubbleable_metadata = NULL) { if (strpos($route_name, 'entity.') === 0 && list(, $entity_type, $operation) = explode('.', $route_name)) { if (isset($parameters[$entity_type]) && strlen($parameters[$entity_type]) === 32) { if ($entities = $this->entityManager->getStorage($entity_type)->loadByProperties(['uuid' => $parameters[$entity_type]])) { diff --git a/core/modules/menu_ui/menu_ui.module b/core/modules/menu_ui/menu_ui.module index 6f31eb5..3481139 100644 --- a/core/modules/menu_ui/menu_ui.module +++ b/core/modules/menu_ui/menu_ui.module @@ -195,8 +195,12 @@ function menu_ui_get_menu_link_defaults(NodeInterface $node) { // Give priority to the default menu $type_menus = $node_type->getThirdPartySetting('menu_ui', 'available_menus', array('main')); if (in_array($menu_name, $type_menus)) { - $query = \Drupal::entityQuery('menu_link_content') - ->condition('link.uri', 'node/' . $node->id()) + $query = \Drupal::entityQuery('menu_link_content'); + $group = $query->orConditionGroup() + ->condition('link.uri', 'entity:node/' . $node->id()) + ->condition('link.uri', 'internal:/node/' . $node->id()) + ->condition('link.uri', 'internal:/node/' . $node->uuid()); + $query->condition($group) ->condition('menu_name', $menu_name) ->sort('id', 'ASC') ->range(0, 1); @@ -206,8 +210,12 @@ function menu_ui_get_menu_link_defaults(NodeInterface $node) { } // Check all allowed menus if a link does not exist in the default menu. if (!$id && !empty($type_menus)) { - $query = \Drupal::entityQuery('menu_link_content') + $query = \Drupal::entityQuery('menu_link_content'); + $group = $query->orConditionGroup() ->condition('link.uri', 'entity:node/' . $node->id()) + ->condition('link.uri', 'internal:/node/' . $node->id()) + ->condition('link.uri', 'internal:/node/' . $node->uuid()); + $query->condition($group) ->condition('menu_name', array_values($type_menus), 'IN') ->sort('id', 'ASC') ->range(0, 1); diff --git a/core/modules/menu_ui/src/Tests/MenuTest.php b/core/modules/menu_ui/src/Tests/MenuTest.php index ef79989..2819fa5 100644 --- a/core/modules/menu_ui/src/Tests/MenuTest.php +++ b/core/modules/menu_ui/src/Tests/MenuTest.php @@ -14,6 +14,7 @@ use Drupal\Core\Menu\MenuLinkInterface; use Drupal\Core\Url; use Drupal\menu_link_content\Entity\MenuLinkContent; +use Drupal\node\Entity\NodeType; use Drupal\system\Entity\Menu; use Drupal\node\Entity\Node; @@ -75,7 +76,7 @@ protected function setUp() { $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article')); // Create users. - $this->adminUser = $this->drupalCreateUser(array('access administration pages', 'administer blocks', 'administer menu', 'create article content')); + $this->adminUser = $this->drupalCreateUser(array('access administration pages', 'administer blocks', 'administer menu', 'create article content', 'edit any article content')); $this->authenticatedUser = $this->drupalCreateUser(array()); } @@ -227,6 +228,14 @@ function addCustomMenu() { // Enable the block. $block = $this->drupalPlaceBlock('system_menu_block:' . $menu_name); $this->blockPlacements[$menu_name] = $block->id(); + + // Make this menu available for node-edit forms. + /* @var \Drupal\node\NodeTypeInterface $type */ + $type = NodeType::load('article'); + $node_menus = $type->getThirdPartySetting('menu_ui', 'available_menus', array('main')); + $node_menus[] = $menu_name; + $type->setThirdPartySetting('menu_ui', 'available_menus', $node_menus); + $type->save(); return Menu::load($menu_name); } @@ -472,6 +481,18 @@ function doMenuTests() { // Save menu links for later tests. $this->items[] = $item1; $this->items[] = $item2; + + // Test links using node/{uuid}. + $node6 = $this->drupalCreateNode(array('type' => 'article')); + $uuid_link = $this->addMenuLink('', '/node/' . $node6->uuid(), $menu_name); + $this->verifyMenuLink($uuid_link, $node6); + $this->drupalGet($node6->url('edit-form')); + $this->assertFieldByName('menu[title]', $uuid_link->label()); + $this->drupalPostForm(NULL, [], t('Save')); + \Drupal::entityManager()->getStorage('menu_link_content')->resetCache([$uuid_link->id()]); + /** @var \Drupal\menu_link_content\MenuLinkContentInterface $uuid_link */ + $uuid_link = MenuLinkContent::load($uuid_link->id()); + $this->assertEqual($uuid_link->getUrlObject(), Url::fromUri('internal:/node/' . $node6->uuid())); } /** diff --git a/core/tests/Drupal/Tests/Core/ParamConverter/EntityConverterTest.php b/core/tests/Drupal/Tests/Core/ParamConverter/EntityConverterTest.php index 04075a8..1365864 100644 --- a/core/tests/Drupal/Tests/Core/ParamConverter/EntityConverterTest.php +++ b/core/tests/Drupal/Tests/Core/ParamConverter/EntityConverterTest.php @@ -112,7 +112,7 @@ public function providerTestConvert() { $data[] = ['valid_id', ['type' => 'entity:entity_test'], ['foo' => 'valid_id'], (object) ['id' => 'valid_id']]; // Invalid ID. $data[] = ['invalid_id', ['type' => 'entity:entity_test'], ['foo' => 'invalid_id'], NULL]; -// Entity type placeholder. + // Entity type placeholder. $data[] = ['valid_id', ['type' => 'entity:{entity_type}'], ['foo' => 'valid_id', 'entity_type' => 'entity_test'], (object) ['id' => 'valid_id']]; // UUID. $data[] = ['1c5217f4-553c-40d8-8389-a3cc3529d79c', ['type' => 'entity:entity_test'], ['foo' => '1c5217f4-553c-40d8-8389-a3cc3529d79c'], (object) ['uuid' => '1c5217f4-553c-40d8-8389-a3cc3529d79c', 'id' => 'valid_id']];