diff --git a/core/includes/menu.inc b/core/includes/menu.inc index d205ac0..1ee610b 100644 --- a/core/includes/menu.inc +++ b/core/includes/menu.inc @@ -964,37 +964,12 @@ 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) { - $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); + return Drupal::service('menu_link.access')->access($route, $href, $map); } /** diff --git a/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkAccess.php b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkAccess.php new file mode 100644 index 0000000..4489756 --- /dev/null +++ b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkAccess.php @@ -0,0 +1,93 @@ +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/menu_link/lib/Drupal/menu_link/MenuLinkBreadcrumbBuilder.php b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkBreadcrumbBuilder.php index acece08..491de28 100644 --- a/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkBreadcrumbBuilder.php +++ b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkBreadcrumbBuilder.php @@ -8,6 +8,11 @@ namespace Drupal\menu_link; use Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface; +use Drupal\Core\Entity\EntityManager; +use Drupal\Core\Routing\RouteProviderInterface; +use Drupal\Core\StringTranslation\TranslationInterface; +use Drupal\menu_link\MenuLinkAccess; +use Symfony\Component\HttpFoundation\Request; /** * Class to define the menu_link breadcrumb builder. @@ -15,12 +20,100 @@ class MenuLinkBreadcrumbBuilder implements BreadcrumbBuilderInterface { /** + * The current request. + * + * @var \Symfony\Component\HttpFoundation\Request + */ + protected $request; + + /** + * The route provider service. + * + * @var \Drupal\Core\Routing\RouteProviderInterface + */ + protected $routeProvider; + + /** + * The menu link storage controller. + * + * @var \Drupal\menu_link\MenuLinkStorageControllerInterface + */ + protected $menuLinkStorage; + + /** + * The menu link access service. + * + * @var \Drupal\menu_link\MenuLinkAccess + */ + protected $menuLinkAccess; + + /** + * The translation manager service. + * + * @var Drupal\Core\StringTranslation\TranslationInterface; + */ + protected $urlGenerator; + + /** + * Constructs the MenuLinkBreadcrumbBuilder. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * The current request. + * @param \Drupal\Core\Routing\RouteProviderInterface $route_provider + * The route provider service. + * @param \Drupal\Core\Entity\EntityManager $entity_manager + * The entity manager service. + * @param \Drupal\menu_link\MenuLinkAccess $menu_link_access + * The menu link access service. + * @param \Drupal\Core\StringTranslation\TranslationInterface $translation + * The translation manager service. + */ + public function __construct(Request $request, RouteProviderInterface $route_provider, EntityManager $entity_manager, MenuLinkAccess $menu_link_access, TranslationInterface $translation) { + $this->request = $request; + $this->routeProvider = $route_provider; + $this->menuLinkStorage = $entity_manager->getStorageController('menu_link'); + $this->menuLinkAccess = $menu_link_access; + $this->translation = $translation; + } + + /** * {@inheritdoc} */ public function build(array $attributes) { - // @todo Rewrite the implementation. - // Currently the result always array. - return menu_get_active_breadcrumb(); + $links = array(); + if ($system_path = $this->request->get('_system_path')) { + $path_elements = explode('/', $system_path); + while (count($path_elements) > 0) { + array_pop($path_elements); + $pattern = implode('/', $path_elements); + $routes = $this->routeProvider->getRoutesByPattern('/' . $pattern); + if (count($routes) > 0) { + // Take the first one. + $routes = $routes->all(); + $route = reset($routes); + continue; + if ($this->menuLinkAccess->access($route, $pattern, $path_elements) && + ($menu_links = $this->menuLinkStorage->loadMultipleByProperties(array( + 'link_path' => $pattern + )))) { + $menu_link = reset($menu_links); + // @todo Replace with link generator service when + // https://drupal.org/node/2047619 lands. + $links[] = l($menu_link->label(), $pattern, $menu_link->options); + } + } + else { + // Legacy hook_menu page callback. + // @todo Remove this once all routes are converted. + $item = menu_get_item($pattern); + $links[] = l($item['title'], $pattern, $item['options']); + } + } + } + // @todo Replace with link generator service when + // https://drupal.org/node/2047619 lands. + $links[] = l($this->translation->translate('Home'), ''); + return array_reverse($links); } } diff --git a/core/modules/menu_link/menu_link.services.yml b/core/modules/menu_link/menu_link.services.yml index a428476..d2d2a9f 100644 --- a/core/modules/menu_link/menu_link.services.yml +++ b/core/modules/menu_link/menu_link.services.yml @@ -1,5 +1,10 @@ services: + menu_link.access: + class: Drupal\menu_link\MenuLinkAccess + arguments: ['@access_manager', '@router.dynamic'] + menu_link.breadcrumb: class: Drupal\menu_link\MenuLinkBreadcrumbBuilder + arguments: ['@request', '@router.route_provider', '@plugin.manager.entity', '@menu_link.access', '@string_translation'] tags: - { name: breadcrumb_builder, priority: 0 }