View source
<?php
namespace Drupal\breadcrumb_manager\Breadcrumb;
use Drupal\breadcrumb_manager\Plugin\BreadcrumbTitleResolverManager;
use Drupal\Component\Plugin\Exception\PluginException;
use Drupal\Core\Access\AccessManagerInterface;
use Drupal\Core\Breadcrumb\Breadcrumb;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Controller\TitleResolverInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
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 Drupal\system\PathBasedBreadcrumbBuilder;
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 BreadcrumbManagerBuilder extends PathBasedBreadcrumbBuilder {
use StringTranslationTrait;
protected $titleResolverManager;
protected $titleResolvers;
protected $breadcrumbConfig;
protected $moduleHandler;
protected $excludedPaths;
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, BreadcrumbTitleResolverManager $title_resolver_manager, ModuleHandlerInterface $module_handler) {
parent::__construct($context, $access_manager, $router, $path_processor, $config_factory, $title_resolver, $current_user, $current_path, $path_matcher);
$this->titleResolverManager = $title_resolver_manager;
$this->titleResolvers = $this->titleResolverManager
->getInstances();
$this->breadcrumbConfig = $config_factory
->get('breadcrumb_manager.config');
$this->moduleHandler = $module_handler;
}
public function applies(RouteMatchInterface $attributes) {
return !$this
->isExcludedPath($attributes
->getRouteObject()
->getPath());
}
public function build(RouteMatchInterface $route_match) {
$breadcrumb = new Breadcrumb();
$breadcrumb
->addCacheContexts([
'url',
]);
$breadcrumb
->addCacheTags([
'config:breadcrumb_manager.config',
]);
$links = [];
$breadcrumb
->addCacheContexts([
'url.path.parent',
]);
if ($this->pathMatcher
->isFrontPage()) {
return $breadcrumb;
}
$path = trim($this->context
->getPathInfo(), '/');
$path_elements = explode('/', $path);
if (!$this->breadcrumbConfig
->get('show_current')) {
array_pop($path_elements);
}
$is_first = TRUE;
while (count($path_elements) > 0) {
$current_path = '/' . implode('/', $path_elements);
array_pop($path_elements);
$show_as_link = $is_first ? $this->breadcrumbConfig
->get('show_current_as_link') : TRUE;
$is_first = FALSE;
$route_request = $this
->getRequestForPath($current_path, $this
->getExcludedPaths());
if ($route_request) {
$route_match = RouteMatch::createFromRequest($route_request);
$access = $this->accessManager
->check($route_match, $this->currentUser, NULL, TRUE);
$breadcrumb = $breadcrumb
->addCacheableDependency($access);
if (!$access
->isAllowed()) {
continue;
}
$title = FALSE;
foreach ($this->titleResolvers as $titleResolver) {
if (!$titleResolver
->isActive()) {
continue;
}
$resolved_title = $titleResolver
->getTitle($current_path, $route_request, $route_match);
if (!empty($resolved_title)) {
$title = $resolved_title;
break;
}
}
if ($title) {
$url = $show_as_link ? Url::fromRouteMatch($route_match) : Url::fromRoute('<none>');
$links[] = new Link($title, $url);
}
}
elseif ($this->breadcrumbConfig
->get('show_fake_segments')) {
try {
$titleResolver = $this->titleResolverManager
->createInstance('raw_path_component');
$current_request = Request::create($current_path);
$title = $titleResolver
->getTitle($current_path, $current_request, $route_match);
$url = Url::fromRoute('<none>');
$this->moduleHandler
->alter('breadcrumb_manager_fake_segments', $current_path, $title, $url);
$links[] = new Link($title, $url);
} catch (PluginException $e) {
}
}
}
if ($this->breadcrumbConfig
->get('show_home')) {
$home = $this->breadcrumbConfig
->get('home') ?: $this
->t('Home');
$links[] = Link::createFromRoute($home, '<front>');
}
return $breadcrumb
->setLinks(array_reverse($links));
}
protected function setExcludedPaths() {
$excluded_paths = $this->breadcrumbConfig
->get('excluded_paths');
$this->excludedPaths = explode("\r\n", $excluded_paths);
if (!$this->breadcrumbConfig
->get('show_front')) {
$this->excludedPaths[] = $this->config
->get('page.front');
}
}
protected function getExcludedPaths() {
if (!isset($this->excludedPaths)) {
$this
->setExcludedPaths();
}
return $this->excludedPaths;
}
protected function isExcludedPath($path) {
$excluded = implode("\n", $this
->getExcludedPaths());
return $this->pathMatcher
->matchPath($path, $excluded);
}
protected function getRequestForPath($path, array $exclude) {
if (in_array($path, $exclude)) {
return NULL;
}
$request = Request::create($path);
$request->headers
->set('Accept', 'text/html');
$processed = $this->pathProcessor
->processInbound($path, $request);
if (empty($processed) || $this
->isExcludedPath($processed)) {
return NULL;
}
$this->currentPath
->setPath($processed, $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;
}
}
}