Mercurial > hg > isophonics-drupal-site
view core/modules/system/src/PathBasedBreadcrumbBuilder.php @ 19:fa3358dc1485 tip
Add ndrum files
author | Chris Cannam |
---|---|
date | Wed, 28 Aug 2019 13:14:47 +0100 |
parents | 129ea1e6d783 |
children |
line wrap: on
line source
<?php namespace Drupal\system; use Drupal\Component\Utility\Unicode; use Drupal\Core\Access\AccessManagerInterface; use Drupal\Core\Breadcrumb\Breadcrumb; use Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface; use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Controller\TitleResolverInterface; use Drupal\Core\Link; use Drupal\Core\ParamConverter\ParamNotConvertedException; use Drupal\Core\Path\CurrentPathStack; use Drupal\Core\Path\PathMatcherInterface; use Drupal\Core\PathProcessor\InboundPathProcessorInterface; use Drupal\Core\Routing\RequestContext; use Drupal\Core\Routing\RouteMatch; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Session\AccountInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\Core\Url; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\Routing\Exception\MethodNotAllowedException; use Symfony\Component\Routing\Exception\ResourceNotFoundException; use Symfony\Component\Routing\Matcher\RequestMatcherInterface; /** * Class to define the menu_link breadcrumb builder. */ class PathBasedBreadcrumbBuilder implements BreadcrumbBuilderInterface { use StringTranslationTrait; /** * The router request context. * * @var \Drupal\Core\Routing\RequestContext */ protected $context; /** * The menu link access service. * * @var \Drupal\Core\Access\AccessManagerInterface */ protected $accessManager; /** * The dynamic router service. * * @var \Symfony\Component\Routing\Matcher\RequestMatcherInterface */ protected $router; /** * The inbound path processor. * * @var \Drupal\Core\PathProcessor\InboundPathProcessorInterface */ protected $pathProcessor; /** * Site config object. * * @var \Drupal\Core\Config\Config */ protected $config; /** * The title resolver. * * @var \Drupal\Core\Controller\TitleResolverInterface */ protected $titleResolver; /** * The current user object. * * @var \Drupal\Core\Session\AccountInterface */ protected $currentUser; /** * The current path service. * * @var \Drupal\Core\Path\CurrentPathStack */ protected $currentPath; /** * The patch matcher service. * * @var \Drupal\Core\Path\PathMatcherInterface */ protected $pathMatcher; /** * Constructs the PathBasedBreadcrumbBuilder. * * @param \Drupal\Core\Routing\RequestContext $context * The router request context. * @param \Drupal\Core\Access\AccessManagerInterface $access_manager * The menu link access service. * @param \Symfony\Component\Routing\Matcher\RequestMatcherInterface $router * The dynamic router service. * @param \Drupal\Core\PathProcessor\InboundPathProcessorInterface $path_processor * The inbound path processor. * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory * The config factory service. * @param \Drupal\Core\Controller\TitleResolverInterface $title_resolver * The title resolver service. * @param \Drupal\Core\Session\AccountInterface $current_user * The current user object. * @param \Drupal\Core\Path\CurrentPathStack $current_path * The current path. * @param \Drupal\Core\Path\PathMatcherInterface $path_matcher * The path matcher service. */ public function __construct(RequestContext $context, AccessManagerInterface $access_manager, RequestMatcherInterface $router, InboundPathProcessorInterface $path_processor, ConfigFactoryInterface $config_factory, TitleResolverInterface $title_resolver, AccountInterface $current_user, CurrentPathStack $current_path, PathMatcherInterface $path_matcher = NULL) { $this->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; $this->pathMatcher = $path_matcher ?: \Drupal::service('path.matcher'); } /** * {@inheritdoc} */ public function applies(RouteMatchInterface $route_match) { return TRUE; } /** * {@inheritdoc} */ public function build(RouteMatchInterface $route_match) { $breadcrumb = new Breadcrumb(); $links = []; // Add the url.path.parent cache context. This code ignores the last path // part so the result only depends on the path parents. $breadcrumb->addCacheContexts(['url.path.parent', 'url.path.is_front']); // Do not display a breadcrumb on the frontpage. if ($this->pathMatcher->isFrontPage()) { return $breadcrumb; } // 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 = []; // 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, NULL, TRUE); // The set of breadcrumb links depends on the access result, so merge // the access result's cacheability metadata. $breadcrumb = $breadcrumb->addCacheableDependency($access); if ($access->isAllowed()) { $title = $this->titleResolver->getTitle($route_request, $route_match->getRouteObject()); 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(['-', '_'], ' ', Unicode::ucfirst(end($path_elements))); } $url = Url::fromRouteMatch($route_match); $links[] = new Link($title, $url); } } } // Add the Home link. $links[] = Link::createFromRoute($this->t('Home'), '<front>'); return $breadcrumb->setLinks(array_reverse($links)); } /** * Matches a path in the router. * * @param string $path * The request path with a leading slash. * @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://www.drupal.org/node/2090293 is // fixed. $request = Request::create($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; } } }