context = $context; $this->accessManager = $access_manager; $this->router = $router; $this->pathProcessor = $path_processor; $this->config = $config_factory->get('system.site'); $this->titleResolver = $title_resolver; $this->currentUser = $current_user; $this->currentPath = $current_path; } /** * {@inheritdoc} */ public function applies(RouteMatchInterface $route_match) { return TRUE; } /** * {@inheritdoc} */ public function build(RouteMatchInterface $route_match) { $links = array(); // General path-based breadcrumbs. Use the actual request path, prior to // resolving path aliases, so the breadcrumb can be defined by simply // creating a hierarchy of path aliases. $path = trim($this->context->getPathInfo(), '/'); $path_elements = explode('/', $path); $exclude = array(); // Don't show a link to the front-page path. $front = $this->config->get('page.front'); $exclude[$front] = TRUE; // /user is just a redirect, so skip it. // @todo Find a better way to deal with /user. $exclude['user'] = TRUE; while (count($path_elements) > 1) { array_pop($path_elements); // Copy the path elements for up-casting. $route_request = $this->getRequestForPath(implode('/', $path_elements), $exclude); if ($route_request) { $route_match = RouteMatch::createFromRequest($route_request); $access = $this->accessManager->check($route_match, $this->currentUser); if ($access) { $title = $this->titleResolver->getTitle($route_request, $route_match->getRouteObject()); } if ($access) { if (!isset($title)) { // Fallback to using the raw path component as the title if the // route is missing a _title or _title_callback attribute. $title = str_replace(array('-', '_'), ' ', Unicode::ucfirst(end($path_elements))); } $url = Url::fromRouteMatch($route_match); $links[] = new Link($title, $url); } } } if ($path && $path != $front) { // Add the Home link, except for the front page. $links[] = Link::createFromRoute($this->t('Home'), ''); } return array_reverse($links); } /** * Matches a path in the router. * * @param string $path * The request path. * @param array $exclude * An array of paths or system paths to skip. * * @return \Symfony\Component\HttpFoundation\Request * A populated request object or NULL if the path couldn't be matched. */ protected function getRequestForPath($path, array $exclude) { if (!empty($exclude[$path])) { return NULL; } // @todo Use the RequestHelper once https://drupal.org/node/2090293 is // fixed. $request = Request::create($this->context->getCompleteBaseUrl() . '/' . $path); // Performance optimization: set a short accept header to reduce overhead in // AcceptHeaderMatcher when matching the request. $request->headers->set('Accept', 'text/html'); // Find the system path by resolving aliases, language prefix, etc. $processed = $this->pathProcessor->processInbound($path, $request); if (empty($processed) || !empty($exclude[$processed])) { // This resolves to the front page, which we already add. return NULL; } $this->currentPath->setPath('/' . $processed, $request); // Attempt to match this path to provide a fully built request. try { $request->attributes->add($this->router->matchRequest($request)); return $request; } catch (ParamNotConvertedException $e) { return NULL; } catch (ResourceNotFoundException $e) { return NULL; } catch (MethodNotAllowedException $e) { return NULL; } catch (AccessDeniedHttpException $e) { return NULL; } } }