diff --git a/core/includes/menu.inc b/core/includes/menu.inc index 6038fa5ff10..66d1e2a525a 100644 --- a/core/includes/menu.inc +++ b/core/includes/menu.inc @@ -777,9 +777,13 @@ function _menu_translate(&$router_item, $map, $to_arg = FALSE) { $router_item['tab_parent_href'] = implode('/', $tab_parent_map); $router_item['options'] = array(); if (!empty($router_item['route_name'])) { + // Route-provided menu items do not have menu loaders, so replace the map + // with the link map. + $map = $link_map; + $route_provider = Drupal::getContainer()->get('router.route_provider'); $route = $route_provider->getRouteByName($router_item['route_name']); - $router_item['access'] = menu_item_route_access($route, $router_item['href']); + $router_item['access'] = menu_item_route_access($route, $router_item['href'], $map); } else { // @todo: Remove once all routes are converted. @@ -917,7 +921,7 @@ function _menu_link_translate(&$item, $translate = FALSE) { // menu_tree_check_access() may set this ahead of time for links to nodes. if (!isset($item['access'])) { if ($route = $item->getRoute()) { - $item['access'] = menu_item_route_access($route, $item['href']); + $item['access'] = menu_item_route_access($route, $item['href'], $map); } elseif (!empty($item['load_functions']) && !_menu_load_objects($item, $map)) { // An error occurred loading an object. @@ -953,23 +957,41 @@ function _menu_link_translate(&$item, $translate = FALSE) { * Router for the given menu item. * @param string $href * Menu path as returned by $item['href'] of menu_get_item(). + * @param array $map + * An array of path arguments, for example, array('node', '5'). * * @return bool * TRUE if the user has access or FALSE if the user should be presented * with access denied. */ -function menu_item_route_access(Route $route, $href) { +function menu_item_route_access(Route $route, $href, &$map) { $request = Request::create('/' . $href); $request->attributes->set('system_path', $href); // Attempt to match this path to provide a fully built request to the // access checker. try { $request->attributes->add(Drupal::service('router.dynamic')->matchRequest($request)); - return Drupal::service('access_manager')->check($route, $request); } catch (NotFoundHttpException $e) { return FALSE; } + + // Populate the map with any matching values from the request. + $path_bits = explode('/', trim($route->getPath(), '/')); + foreach ($map as $index => $map_item) { + $matches = array(); + // Search for placeholders wrapped by curly braces. For example, a path + // 'foo/{bar}/baz' would return 'bar'. + if (isset($path_bits[$index]) && preg_match('/{(?.*)}/', $path_bits[$index], $matches)) { + // If that placeholder is present on the request attributes, replace the + // placeholder in the map with the value. + if ($request->attributes->has($matches['placeholder'])) { + $map[$index] = $request->attributes->get($matches['placeholder']); + } + } + } + + return Drupal::service('access_manager')->check($route, $request); } /** diff --git a/core/modules/field_ui/field_ui.module b/core/modules/field_ui/field_ui.module index fefd9a198a0..7f617aea5ca 100644 --- a/core/modules/field_ui/field_ui.module +++ b/core/modules/field_ui/field_ui.module @@ -83,7 +83,7 @@ function field_ui_menu() { 'weight' => 1, ); $items["$path/fields/%"] = array( - 'title callback' => 'field_ui_instance_title', + 'title callback' => 'entity_page_label', 'title arguments' => array($field_position), 'route_name' => "field_ui.instance_edit.$entity_type", ); @@ -209,16 +209,6 @@ function field_ui_instance_load($field_name, $entity_type, $bundle_name, $bundle return FALSE; } -/** - * Title callback: Returns the name of a given instance. - * - * @see field_ui_menu() - */ -function field_ui_instance_title($instance) { - $entity = entity_load('field_instance', $instance); - return $entity->label(); -} - /** * Implements hook_theme(). */ diff --git a/core/modules/system/lib/Drupal/system/Tests/Menu/LocalActionTest.php b/core/modules/system/lib/Drupal/system/Tests/Menu/LocalActionTest.php index 43ce3a3e21d..81fe57dab6e 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Menu/LocalActionTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Menu/LocalActionTest.php @@ -37,6 +37,7 @@ class LocalActionTest extends WebTestBase { $this->drupalGet('menu-test-local-action'); // Ensure that both menu and route based actions are shown. $this->assertLocalAction(array( + 'menu-test-local-action/dynamic-title' => 'My dynamic-title action', 'menu-test-local-action/hook_menu' => 'My hook_menu action', 'menu-test-local-action/routing' => 'My routing action', )); diff --git a/core/modules/system/tests/modules/menu_test/menu_test.module b/core/modules/system/tests/modules/menu_test/menu_test.module index efafe6b2b43..b5c0c47f900 100644 --- a/core/modules/system/tests/modules/menu_test/menu_test.module +++ b/core/modules/system/tests/modules/menu_test/menu_test.module @@ -432,9 +432,25 @@ function menu_test_menu() { 'type' => MENU_LOCAL_ACTION, ); + $items['menu-test-local-action/dynamic-title'] = array( + 'title' => 'My dynamic title action', + 'title callback' => 'menu_test_local_action_dynamic_title', + 'title arguments' => array(1), + 'route_name' => 'menu_test_local_action4', + 'weight' => -10, + 'type' => MENU_LOCAL_ACTION, + ); + return $items; } +/** + * Title callback: Set a dynamic title for a local action. + */ +function menu_test_local_action_dynamic_title($arg) { + return t('My @arg action', array('@arg' => $arg)); +} + /** * Implements hook_local_actions(). */ diff --git a/core/modules/system/tests/modules/menu_test/menu_test.routing.yml b/core/modules/system/tests/modules/menu_test/menu_test.routing.yml index 09b42ba8a29..3154626e98b 100644 --- a/core/modules/system/tests/modules/menu_test/menu_test.routing.yml +++ b/core/modules/system/tests/modules/menu_test/menu_test.routing.yml @@ -37,3 +37,10 @@ menu_test_local_action3: _content: '\Drupal\menu_test\TestControllers::test2' requirements: _access: 'TRUE' + +menu_test_local_action4: + pattern: '/menu-test-local-action/dynamic-title' + defaults: + _content: '\Drupal\menu_test\TestControllers::test2' + requirements: + _access: 'TRUE'