diff --git a/core/core.services.yml b/core/core.services.yml index a236f47..23ce7bf 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -175,9 +175,6 @@ services: plugin.manager.menu.local_task: class: Drupal\Core\Menu\LocalTaskManager arguments: ['@container.namespaces', '@controller_resolver', '@request', '@router.route_provider', '@module_handler'] - menu_link.access: - class: Drupal\Core\Menu\MenuLinkAccess - arguments: ['@access_manager', '@router.dynamic'] request: class: Symfony\Component\HttpFoundation\Request # @TODO the synthetic setting must be uncommented whenever drupal_session_initialize() diff --git a/core/includes/menu.inc b/core/includes/menu.inc index 5000567..ccc40f8 100644 --- a/core/includes/menu.inc +++ b/core/includes/menu.inc @@ -963,13 +963,37 @@ function _menu_link_translate(&$item, $translate = FALSE) { * TRUE if the user has access or FALSE if the user should be presented * with access denied. * - * @deprecated Use \Drupal::service('menu_link.access')->access() instead. - * * @throws \Symfony\Component\Routing\Exception\ResourceNotFoundException * If the system path in $href does not match the $route. */ function menu_item_route_access(Route $route, $href, &$map) { - return Drupal::service('menu_link.access')->access($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)); + } + 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/lib/Drupal/Core/Menu/MenuLinkAccess.php b/core/lib/Drupal/Core/Menu/MenuLinkAccess.php deleted file mode 100644 index 980da87..0000000 --- a/core/lib/Drupal/Core/Menu/MenuLinkAccess.php +++ /dev/null @@ -1,93 +0,0 @@ -accessManager = $access_manager; - $this->dynamicRouter = $dynamic_router; - } - - /** - * Checks access to a menu item by mocking a request for a path. - * - * @param \Symfony\Component\Routing\Route $route - * Router for the given menu item. - * @param string $href - * Menu path as returned by link_path of the menu 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. - * - * @throws \Symfony\Component\Routing\Exception\ResourceNotFoundException - * If the system path in $href does not match the $route. - */ - public function 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($this->dynamicRouter->matchRequest($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 $this->accessManager->check($route, $request); - } - -} diff --git a/core/modules/book/book.services.yml b/core/modules/book/book.services.yml index 71de5a0..9ecb30d 100644 --- a/core/modules/book/book.services.yml +++ b/core/modules/book/book.services.yml @@ -1,7 +1,7 @@ services: book.breadcrumb: class: Drupal\book\BookBreadcrumbBuilder - arguments: ['@router.route_provider', '@plugin.manager.entity', '@menu_link.access', '@string_translation'] + arguments: ['@router.route_provider', '@plugin.manager.entity', '@access_manager', '@string_translation'] tags: - { name: breadcrumb_builder, priority: 701 } book.manager: diff --git a/core/modules/book/lib/Drupal/book/BookBreadcrumbBuilder.php b/core/modules/book/lib/Drupal/book/BookBreadcrumbBuilder.php index 87bee26..0056065 100644 --- a/core/modules/book/lib/Drupal/book/BookBreadcrumbBuilder.php +++ b/core/modules/book/lib/Drupal/book/BookBreadcrumbBuilder.php @@ -38,15 +38,11 @@ public function build(array $attributes) { if (!empty($menu_link->route_name)) { try { if ($route = $this->routeProvider->getRouteByName($menu_link->route_name)) { - try { - if ($this->menuLinkAccess->access($route, $menu_link->link_path, $path_elements)) { - // @todo Replace with link generator service when - // https://drupal.org/node/2047619 lands. - $links[] = l($menu_link->label(), $menu_link->link_path, $menu_link->options); - } - } - catch (NotFoundHttpException $e) { - continue; + $parameters = $this->getNamedParameters($route, $path_elements); + if ($this->accessManager->checkNamedRoute($menu_link->route_name, $parameters)) { + // @todo Replace with link generator service when + // https://drupal.org/node/2047619 lands. + $links[] = l($menu_link->label(), $menu_link->link_path, $menu_link->options); } } } diff --git a/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkBreadcrumbBuilder.php b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkBreadcrumbBuilder.php index a6daf44..ac94afc 100644 --- a/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkBreadcrumbBuilder.php +++ b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkBreadcrumbBuilder.php @@ -12,9 +12,10 @@ use Drupal\Core\Routing\RouteProviderInterface; use Drupal\Core\Routing\RouteCompiler; use Drupal\Core\StringTranslation\TranslationInterface; -use Drupal\Core\Menu\MenuLinkAccess; +use Drupal\Core\Access\AccessManager; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\Routing\Exception\RouteNotFoundException; +use Symfony\Component\Routing\Route; /** * Class to define the menu_link breadcrumb builder. @@ -38,9 +39,9 @@ class MenuLinkBreadcrumbBuilder implements BreadcrumbBuilderInterface { /** * The menu link access service. * - * @var \Drupal\menu_link\MenuLinkAccess + * @var \Drupal\Core\Access\AccessManager */ - protected $menuLinkAccess; + protected $accessManager; /** * The translation manager service. @@ -63,15 +64,15 @@ class MenuLinkBreadcrumbBuilder implements BreadcrumbBuilderInterface { * The route provider service. * @param \Drupal\Core\Entity\EntityManager $entity_manager * The entity manager service. - * @param \Drupal\menu_link\MenuLinkAccess $menu_link_access + * @param \Drupal\Core\Access\AccessManager $access_manager * The menu link access service. * @param \Drupal\Core\StringTranslation\TranslationInterface $translation * The translation manager service. */ - public function __construct(RouteProviderInterface $route_provider, EntityManager $entity_manager, MenuLinkAccess $menu_link_access, TranslationInterface $translation) { + public function __construct(RouteProviderInterface $route_provider, EntityManager $entity_manager, AccessManager $access_manager, TranslationInterface $translation) { $this->routeProvider = $route_provider; $this->menuLinkStorage = $entity_manager->getStorageController('menu_link'); - $this->menuLinkAccess = $menu_link_access; + $this->accessManager = $access_manager; $this->translation = $translation; $this->menuStorage = $entity_manager->getStorageController('menu'); } @@ -99,7 +100,6 @@ public function build(array $attributes) { while (count($path_elements) > 0) { array_pop($path_elements); // Copy the path elements for up-casting. - $map = $path_elements; $pattern = implode('/', $path_elements); $menu_links = $this->menuLinkStorage->loadByProperties(array( 'link_path' => $pattern, @@ -120,29 +120,24 @@ public function build(array $attributes) { } catch (NotFoundHttpException $e) {} } - if (count($menu_links) > 0) { - $menu_link = reset($menu_links); - if (!empty($menu_link->route_name)) { - try { - if ($route = $this->routeProvider->getRouteByName($menu_link->route_name)) { - try { - // This will upcast the path elements. - if ($this->menuLinkAccess->access($route, $pattern, $map)) { - // @todo Move _menu_item_localize() to a service. - _menu_item_localize($menu_link, $map, FALSE); - // @todo Replace with link generator service when - // https://drupal.org/node/2047619 lands. - $links[] = l($menu_link->title, $pattern, $menu_link->options); - } - } - catch (NotFoundHttpException $e) { - continue; - } + if (count($menu_links) > 0 && ($menu_link = reset($menu_links)) && !empty($menu_link->route_name)) { + try { + if ($route = $this->routeProvider->getRouteByName($menu_link->route_name)) { + $parameters = $this->getNamedParameters($route, $path_elements); + if ($this->accessManager->checkNamedRoute($menu_link->route_name, $parameters)) { + // _menu_item_localize expects an upcasted map. + $map = $path_elements; + $this->upcastParameters($route, $attributes, $map); + // @todo Move _menu_item_localize() to a service. + _menu_item_localize($menu_link, $map, FALSE); + // @todo Replace with link generator service when + // https://drupal.org/node/2047619 lands. + $links[] = l($menu_link->title, $pattern, $menu_link->options); } } - catch (RouteNotFoundException $e) { - continue; - } + } + catch (RouteNotFoundException $e) { + continue; } } else { @@ -165,4 +160,63 @@ public function build(array $attributes) { return array_reverse($links); } + /** + * Upcasts the path elements from their raw form. + * + * Path map is of form array('node', 1) when passed in. After upcasting raw + * values are replaced with their actual objects for example array('node', 1) + * would become array('node', \Drupal\node\Entity\Node); + * + * @param \Symfony\Component\Routing\Route $route + * The route object. + * @param array $attributes + * The request attributes. + * @param array $map + * The raw path map which is to be upcast. + */ + protected function upcastParameters(Route $route, array $attributes, array &$map) { + // 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 (!empty($attributes[$matches['placeholder']])) { + $map[$index] = $attributes[$matches['placeholder']]; + } + } + } + } + + /** + * Returns a named map of placeholder values. + * + * Path map is of form array('node', 1) when passed in. After mapping values + * that correspond with named placeholders in the path are returned, keyed by + * the placeholder name. For example array('node', 1) for path node/{node} + * would be returned as array('node' => 1). + * + * @param \Symfony\Component\Routing\Route $route + * The route object. + * @param array $map + * The path map, eg array('node', 1) for /node/1. + */ + protected function getNamedParameters(Route $route, array $map) { + // Populate the map with any matching values from the request. + $path_bits = explode('/', trim($route->getPath(), '/')); + $named = array(); + 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)) { + $named[$matches['placeholder']] = $map_item; + } + } + return $named; + } + } diff --git a/core/modules/menu_link/menu_link.services.yml b/core/modules/menu_link/menu_link.services.yml index f3c48f8..272f249 100644 --- a/core/modules/menu_link/menu_link.services.yml +++ b/core/modules/menu_link/menu_link.services.yml @@ -1,6 +1,6 @@ services: menu_link.breadcrumb: class: Drupal\menu_link\MenuLinkBreadcrumbBuilder - arguments: ['@router.route_provider', '@plugin.manager.entity', '@menu_link.access', '@string_translation'] + arguments: ['@router.route_provider', '@plugin.manager.entity', '@access_manager', '@string_translation'] tags: - { name: breadcrumb_builder, priority: 0 }