public function EasyBreadcrumbBuilder::build in Easy Breadcrumb 8
Same name and namespace in other branches
- 2.x src/EasyBreadcrumbBuilder.php \Drupal\easy_breadcrumb\EasyBreadcrumbBuilder::build()
Builds the breadcrumb.
Parameters
\Drupal\Core\Routing\RouteMatchInterface $route_match: The current route match.
Return value
\Drupal\Core\Breadcrumb\Breadcrumb A breadcrumb.
Overrides BreadcrumbBuilderInterface::build
File
- src/
EasyBreadcrumbBuilder.php, line 259
Class
- EasyBreadcrumbBuilder
- Primary implementation for the Easy Breadcrumb builder.
Namespace
Drupal\easy_breadcrumbCode
public function build(RouteMatchInterface $route_match) {
$breadcrumb = new Breadcrumb();
$links = [];
$exclude = [];
$curr_lang = $this->languageManager
->getCurrentLanguage()
->getId();
$replacedTitles = [];
$mapValues = preg_split('/[\\r\\n]+/', $this->config
->get(EasyBreadcrumbConstants::REPLACED_TITLES));
$limit_display = $this->config
->get(EasyBreadcrumbConstants::LIMIT_SEGMENT_DISPLAY);
$segment_limit = $this->config
->get(EasyBreadcrumbConstants::SEGMENT_DISPLAY_LIMIT);
foreach ($mapValues as $mapValue) {
$values = explode("::", $mapValue);
if (count($values) == 2) {
$replacedTitles[$values[0]] = $values[1];
}
}
// Set request context from the $route_match if route is available.
$this
->setRouteContextFromRouteMatch($route_match);
// General path-based breadcrumbs. Use the actual request path, prior to
// resolving path aliases so the breadcrumb can be defined by creating a
// hierarchy of path aliases.
$path = trim($this->context
->getPathInfo(), '/');
$path = urldecode($path);
$path_elements = explode('/', $path);
$front = $this->siteConfig
->get('page.front');
// Give the option to keep the breadcrumb on the front page.
$keep_front = !empty($this->config
->get(EasyBreadcrumbConstants::HOME_SEGMENT_TITLE)) && $this->config
->get(EasyBreadcrumbConstants::HOME_SEGMENT_KEEP);
$exclude[$front] = $keep_front;
$exclude[''] = !$keep_front;
$exclude['/user'] = TRUE;
// See if we are doing a Custom Path override.
$path_crumb_row = preg_split('/[\\r\\n]+/', $this->config
->get(EasyBreadcrumbConstants::CUSTOM_PATHS));
$path_crumb_row = array_filter($path_crumb_row);
foreach ($path_crumb_row as $path_crumb) {
$values = explode("::", $path_crumb);
// Shift path off array.
$custom_path = array_shift($values);
// Strip of leading/ending slashes and spaces/tabs (allows indenting
// rows on config page).
$custom_path = mb_strtolower(trim($custom_path, "/ \t"));
// Check if custom path includes the flag used to signify that the
// path is expressed as a regular expression pattern.
$regex_match = [];
$is_regex = preg_match('/^regex\\s*!\\s*\\/(.*)/', $custom_path, $regex_match);
if ($is_regex) {
$custom_path = $regex_match[1];
$regex_group_matches = [];
}
// If the path matches the current path, build the breadcrumbs.
if ($is_regex && preg_match("|" . $custom_path . "|", $path, $regex_group_matches) || !$is_regex && $path == $custom_path) {
if ($this->config
->get(EasyBreadcrumbConstants::INCLUDE_HOME_SEGMENT)) {
$links[] = Link::createFromRoute($this->config
->get(EasyBreadcrumbConstants::HOME_SEGMENT_TITLE), '<front>');
}
if ($is_regex && count($regex_group_matches) > 1) {
// Discard first element as that's the full matched string
// rather than a captured group.
array_shift($regex_group_matches);
}
// Get $title|[$url] pairs from $values.
foreach ($values as $pair) {
$settings = explode("|", $pair);
$title = Html::decodeEntities(Xss::filter(trim($settings[0])));
$use_current_page_title = trim($settings[0]) === '<title>';
// If the custom title uses the current page title, fetch it.
if ($use_current_page_title) {
$route_request = $this
->getRequestForPath($path, []);
if ($route_request) {
$route_match = RouteMatch::createFromRequest($route_request);
$access = $this->accessManager
->check($route_match, $this->currentUser, NULL, TRUE);
$breadcrumb = $breadcrumb
->addCacheableDependency($access);
// The set of breadcrumb links depends on the access result, so merge
// the access result's cacheability metadata.
if ($access
->isAllowed()) {
if ($this->config
->get(EasyBreadcrumbConstants::TITLE_FROM_PAGE_WHEN_AVAILABLE)) {
$title = $this
->normalizeText($this
->getTitleString($route_request, $route_match, $replacedTitles));
}
}
}
}
elseif ($is_regex) {
foreach ($regex_group_matches as $group_num => $captured_str) {
$title = str_replace('$' . ($group_num + 1), urlencode($captured_str), $title);
}
}
// Get URL if it is provided.
$url = '';
if (isset($settings[1])) {
$url = trim($settings[1]);
// If the custom path includes any regex match groups
// (eg. "/foo/(\d*)/bar") then check if the urls for any segments
// have matched group variables (eg. $1 or $3) and if they do
// substitute them out for the the corresponding
// matched strings.
if ($is_regex) {
foreach ($regex_group_matches as $group_num => $captured_str) {
$url = str_replace('$' . ($group_num + 1), urlencode($captured_str), $url);
}
}
// If URL is invalid, then display warning and disable the link.
if (!UrlHelper::isValid($url)) {
$this->messenger
->addWarning($this
->t("EasyBreadcrumb: Custom crumb for @path URL '@url' is invalid.", [
'@path' => $path,
'@url' => $url,
]));
$url = '';
}
// If URL is not start with slash then display warning
// and disable the link.
if ($url[0] != '/') {
$this->messenger
->addWarning($this
->t("EasyBreadcrumb: Custom crumb for @path URL '@url' should start with slash(/).", [
'@path' => $path,
'@url' => $url,
]));
$url = '';
}
}
if ($url) {
$links[] = new Link($title, Url::fromUserInput($url, [
'absolute' => TRUE,
]));
}
else {
$links[] = Link::createFromRoute($title, '<none>');
}
}
// Handle views path expiration cache expiration.
$parameters = $route_match
->getParameters();
foreach ($parameters as $key => $parameter) {
if ($key === 'view_id') {
$breadcrumb
->addCacheTags([
'config:views.view.' . $parameter,
]);
}
if ($parameter instanceof CacheableDependencyInterface) {
$breadcrumb
->addCacheableDependency($parameter);
}
}
// Expire cache by languages and config changes.
$breadcrumb
->addCacheContexts([
'route',
'url.path',
'languages',
]);
// Expire cache context for config changes.
$breadcrumb
->addCacheableDependency($this->config);
return $breadcrumb
->setLinks($links);
}
}
// Handle views path expiration cache expiration.
$parameters = $route_match
->getParameters();
foreach ($parameters as $key => $parameter) {
if ($key === 'view_id') {
$breadcrumb
->addCacheTags([
'config:views.view.' . $parameter,
]);
}
if ($parameter instanceof CacheableDependencyInterface) {
$breadcrumb
->addCacheableDependency($parameter);
}
}
// Expire cache by languages and config changes.
$breadcrumb
->addCacheContexts([
'route',
'url.path',
'languages',
]);
$breadcrumb
->addCacheableDependency($this->config);
$i = 0;
$add_langcode = FALSE;
// Remove the current page if it's not wanted.
if (!$this->config
->get(EasyBreadcrumbConstants::INCLUDE_TITLE_SEGMENT)) {
array_pop($path_elements);
}
if (isset($path_elements[0])) {
// Remove the first parameter if it matches the current language.
if (!$this->config
->get(EasyBreadcrumbConstants::LANGUAGE_PATH_PREFIX_AS_SEGMENT)) {
if (mb_strtolower($path_elements[0]) == mb_strtolower($curr_lang)) {
// Preserve case in language to allow path matching to work properly.
$curr_lang = $path_elements[0];
array_shift($path_elements);
$add_langcode = TRUE;
}
}
}
// Remove leading breadcrumb segments by limiting the following loop.
$loop_limit = $limit_display && isset($segment_limit) ? $segment_limit : 0;
while (count($path_elements) > $loop_limit) {
$check_path = '/' . implode('/', $path_elements);
if ($add_langcode) {
$check_path = '/' . $curr_lang . $check_path;
}
// Copy the path elements for up-casting.
$route_request = $this
->getRequestForPath($check_path, $exclude);
if ($this->config
->get(EasyBreadcrumbConstants::EXCLUDED_PATHS)) {
$config_textarea = $this->config
->get(EasyBreadcrumbConstants::EXCLUDED_PATHS);
$excludes = preg_split('/[\\r\\n]+/', $config_textarea, -1, PREG_SPLIT_NO_EMPTY);
if (in_array(end($path_elements), $excludes)) {
array_pop($path_elements);
continue;
}
}
if ($route_request) {
$route_match = RouteMatch::createFromRequest($route_request);
$access = $this->accessManager
->check($route_match, $this->currentUser, NULL, TRUE);
$breadcrumb = $breadcrumb
->addCacheableDependency($access);
// The set of breadcrumb links depends on the access result, so merge
// the access result's cacheability metadata.
if ($access
->isAllowed()) {
if ($this->config
->get(EasyBreadcrumbConstants::TITLE_FROM_PAGE_WHEN_AVAILABLE)) {
// Get the title if the current route represents an entity.
if (($route = $route_match
->getRouteObject()) && ($parameters = $route
->getOption('parameters'))) {
foreach ($parameters as $name => $options) {
if (isset($options['type']) && strpos($options['type'], 'entity:') === 0) {
$entity = $route_match
->getParameter($name);
if ($entity instanceof ContentEntityInterface && $entity
->hasLinkTemplate('canonical')) {
$title = $entity
->label();
if ($this->config
->get(EasyBreadcrumbConstants::TRUNCATOR_MODE)) {
$title = $this
->truncator($title);
}
break;
}
}
}
}
else {
$title = $this
->normalizeText($this
->getTitleString($route_request, $route_match, $replacedTitles));
if ($this->config
->get(EasyBreadcrumbConstants::TRUNCATOR_MODE)) {
$title = $this
->truncator($title);
}
if (empty($title)) {
unset($title);
}
// If the title is to be replaced...
if (!empty($title) && array_key_exists($title, $replacedTitles)) {
// Replaces the title.
$title = $replacedTitles[(string) $title];
}
}
}
if (!isset($title)) {
if ($this->config
->get(EasyBreadcrumbConstants::USE_MENU_TITLE_AS_FALLBACK)) {
// Try resolve the menu title from the route.
$route_name = $route_match
->getRouteName();
$route_parameters = $route_match
->getRawParameters()
->all();
$menu_links = $this->menuLinkManager
->loadLinksByRoute($route_name, $route_parameters);
if (empty($menu_links)) {
if ($this->config
->get(EasyBreadcrumbConstants::USE_PAGE_TITLE_AS_MENU_TITLE_FALLBACK)) {
$title = $this
->getTitleString($route_request, $route_match, $replacedTitles);
if (!empty($title) && array_key_exists($title, $replacedTitles)) {
$title = $replacedTitles[$title];
}
if (!empty($title) && $this->config
->get(EasyBreadcrumbConstants::TRUNCATOR_MODE)) {
$title = $this
->truncator($title);
}
}
}
else {
$menu_link = reset($menu_links);
$title = $this
->normalizeText($menu_link
->getTitle());
if (array_key_exists($title, $replacedTitles)) {
$title = $replacedTitles[$title];
}
if ($this->config
->get(EasyBreadcrumbConstants::TRUNCATOR_MODE)) {
$title = $this
->truncator($title);
}
}
}
// Fallback to using the raw path component as the title if the
// route is missing a _title or _title_callback attribute.
if (!isset($title)) {
$title = $this
->normalizeText(end($path_elements));
if (array_key_exists($title, $replacedTitles)) {
$title = $replacedTitles[$title];
}
if ($this->config
->get(EasyBreadcrumbConstants::TRUNCATOR_MODE)) {
$title = $this
->truncator($title);
}
}
}
// Add a linked breadcrumb unless it's the current page.
if ($i == 0 && $this->config
->get(EasyBreadcrumbConstants::INCLUDE_TITLE_SEGMENT) && !$this->config
->get(EasyBreadcrumbConstants::TITLE_SEGMENT_AS_LINK)) {
$title = $this
->truncator($title);
$links[] = Link::createFromRoute($title, '<none>');
}
elseif ($route_match
->getRouteObject()) {
$url = Url::fromRouteMatch($route_match);
if ($this->config
->get(EasyBreadcrumbConstants::ABSOLUTE_PATHS)) {
$url
->setOption('absolute', TRUE);
}
$title = $this
->truncator($title);
$links[] = new Link($title, $url);
}
// Add all term parents.
if ($i == 0 && $this->config
->get(EasyBreadcrumbConstants::TERM_HIERARCHY) && ($term = $route_match
->getParameter('taxonomy_term'))) {
$parents = $this->entityTypeManager
->getStorage('taxonomy_term')
->loadAllParents($term
->id());
// Unset current term.
array_shift($parents);
foreach ($parents as $parent) {
$parent = $this->entityRepository
->getTranslationFromContext($parent);
$links[] = $parent
->toLink();
}
}
unset($title);
$i++;
}
}
elseif ($this->config
->get(EasyBreadcrumbConstants::INCLUDE_INVALID_PATHS) && empty($exclude[implode('/', $path_elements)])) {
$title = $this
->normalizeText(end($path_elements));
$this
->applyTitleReplacement($title, $replacedTitles);
$links[] = Link::createFromRoute($title, '<none>');
unset($title);
}
array_pop($path_elements);
}
// Add the home link, if desired.
if ($this->config
->get(EasyBreadcrumbConstants::INCLUDE_HOME_SEGMENT)) {
if ($path && '/' . $path != $front && $path != $curr_lang) {
if (!$this->config
->get(EasyBreadcrumbConstants::USE_SITE_TITLE)) {
$links[] = Link::createFromRoute($this
->normalizeText($this->config
->get(EasyBreadcrumbConstants::HOME_SEGMENT_TITLE)), '<front>');
}
else {
$links[] = Link::createFromRoute($this->siteConfig
->get('name'), '<front>');
}
}
if ($this->config
->get(EasyBreadcrumbConstants::HIDE_SINGLE_HOME_ITEM) && count($links) === 1) {
return $breadcrumb
->setLinks([]);
}
}
$links = array_reverse($links);
if ($this->config
->get(EasyBreadcrumbConstants::REMOVE_REPEATED_SEGMENTS)) {
$links = $this
->removeRepeatedSegments($links);
}
return $breadcrumb
->setLinks($links);
}