class EasyBreadcrumbBuilder in Easy Breadcrumb 8
Same name and namespace in other branches
- 2.x src/EasyBreadcrumbBuilder.php \Drupal\easy_breadcrumb\EasyBreadcrumbBuilder
Primary implementation for the Easy Breadcrumb builder.
Hierarchy
- class \Drupal\easy_breadcrumb\EasyBreadcrumbBuilder implements BreadcrumbBuilderInterface uses StringTranslationTrait
Expanded class hierarchy of EasyBreadcrumbBuilder
1 file declares its use of EasyBreadcrumbBuilder
- EasyBreadcrumbBuilderTest.php in tests/
src/ Kernel/ EasyBreadcrumbBuilderTest.php
1 string reference to 'EasyBreadcrumbBuilder'
1 service uses EasyBreadcrumbBuilder
File
- src/
EasyBreadcrumbBuilder.php, line 47
Namespace
Drupal\easy_breadcrumbView source
class EasyBreadcrumbBuilder implements BreadcrumbBuilderInterface {
use StringTranslationTrait;
/**
* The router request context.
*
* @var \Drupal\Core\Routing\RequestContext
*/
protected $context;
/**
* The access manager service.
*
* @var \Drupal\Core\Access\AccessManagerInterface
*/
protected $accessManager;
/**
* The request stack service.
*
* @var \Symfony\Component\HttpFoundation\RequestStack
*/
protected $requestStack;
/**
* The dynamic router service.
*
* @var \Symfony\Component\Routing\Matcher\RequestMatcherInterface
*/
protected $router;
/**
* The path processor service.
*
* @var \Drupal\Core\PathProcessor\InboundPathProcessorInterface
*/
protected $pathProcessor;
/**
* Site config object.
*
* @var \Drupal\Core\Config\Config
*/
protected $siteConfig;
/**
* Breadcrumb config object.
*
* @var \Drupal\Core\Config\Config
*/
protected $config;
/**
* The title resolver.
*
* @var \Drupal\easy_breadcrumb\TitleResolver
*/
protected $titleResolver;
/**
* The current user object.
*
* @var \Drupal\Core\Session\AccountInterface
*/
protected $currentUser;
/**
* The current path object.
*
* @var \Drupal\Core\Path\CurrentPathStack
*/
protected $currentPath;
/**
* The menu link manager.
*
* @var \Drupal\Core\Menu\MenuLinkManager
*/
protected $menuLinkManager;
/**
* The language manager.
*
* @var \Drupal\Core\Language\LanguageManagerInterface
*/
protected $languageManager;
/**
* The logger service.
*
* @var \Drupal\Core\Logger\LoggerChannelFactoryInterface
*/
protected $logger;
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* The entity repository.
*
* @var \Drupal\Core\Entity\EntityRepositoryInterface
*/
protected $entityRepository;
/**
* The messenger service.
*
* @var \Drupal\Core\Messenger\MessengerInterface
*/
protected $messenger;
/**
* The module handler service.
*
* @var \Drupal\Core\Extension\ModuleHandler
*/
protected $moduleHandler;
/**
* Constructs the EasyBreadcrumbBuilder.
*
* @param \Drupal\Core\Routing\RequestContext $context
* The router request context.
* @param \Drupal\Core\Access\AccessManagerInterface $access_manager
* The access manager service.
* @param \Symfony\Component\Routing\Matcher\RequestMatcherInterface $router
* The dynamic router service.
* @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
* The request stack 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\easy_breadcrumb\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\Menu\MenuLinkManager $menu_link_manager
* The menu link manager.
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager service.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
* The entity repository.
* @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger
* The logger service.
* @param \Drupal\Core\Messenger\MessengerInterface $messenger
* The messenger service.
* @param \Drupal\Core\Extension\ModuleHandler $module_handler
* The module handler.
*/
public function __construct(RequestContext $context, AccessManagerInterface $access_manager, RequestMatcherInterface $router, RequestStack $request_stack, InboundPathProcessorInterface $path_processor, ConfigFactoryInterface $config_factory, TitleResolverInterface $title_resolver, AccountInterface $current_user, CurrentPathStack $current_path, MenuLinkManager $menu_link_manager, LanguageManagerInterface $language_manager, EntityTypeManagerInterface $entity_type_manager, EntityRepositoryInterface $entity_repository, LoggerChannelFactoryInterface $logger, MessengerInterface $messenger, ModuleHandler $module_handler) {
$this->context = $context;
$this->accessManager = $access_manager;
$this->router = $router;
$this->requestStack = $request_stack;
$this->pathProcessor = $path_processor;
$this->siteConfig = $config_factory
->get('system.site');
$this->config = $config_factory
->get(EasyBreadcrumbConstants::MODULE_SETTINGS);
$this->titleResolver = $title_resolver;
$this->currentUser = $current_user;
$this->currentPath = $current_path;
$this->menuLinkManager = $menu_link_manager;
$this->languageManager = $language_manager;
$this->entityTypeManager = $entity_type_manager;
$this->entityRepository = $entity_repository;
$this->logger = $logger;
$this->messenger = $messenger;
$this->moduleHandler = $module_handler;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static($definition = $container
->getDefinition('easy_breadcrumb.title_resolver'), $definition
->setClass('Drupal\\easy_breadcrumb\\TitleResolver'));
}
/**
* {@inheritdoc}
*/
public function applies(RouteMatchInterface $route_match) {
$applies_admin_routes = $this->config
->get(EasyBreadcrumbConstants::APPLIES_ADMIN_ROUTES);
// If never set before ensure Applies to administration pages is on.
if (!isset($applies_admin_routes)) {
return TRUE;
}
$request = $this->requestStack
->getCurrentRequest();
$route = $request->attributes
->get(RouteObjectInterface::ROUTE_OBJECT);
if ($route && $route
->getOption('_admin_route') && $applies_admin_routes == FALSE) {
return FALSE;
}
return TRUE;
}
/**
* {@inheritdoc}
*/
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);
}
/**
* Set request context from passed in $route_match if route is available.
*
* @param Drupal\Core\Routing\RouteMatchInterface $route_match
* The route match for the breadcrumb.
*/
protected function setRouteContextFromRouteMatch(RouteMatchInterface $route_match) {
try {
$url = $route_match
->getRouteObject() ? Url::fromRouteMatch($route_match) : NULL;
if ($url && ($request = $this
->getRequestForPath($url
->toString(), []))) {
$route_match_context = new RequestContext();
$route_match_context
->fromRequest($request);
$this->context = $route_match_context;
}
} catch (RouteNotFoundException $e) {
// Ignore the exception.
}
}
/**
* Apply title replacements.
*
* @param string $title
* Page title.
* @param array $replacements
* Replacement rules map.
*/
public function applyTitleReplacement(&$title, array $replacements) {
if (!is_string($title)) {
return;
}
if (array_key_exists($title, $replacements)) {
$title = $replacements[$title];
}
}
/**
* Get string title for route.
*
* @param \Symfony\Component\HttpFoundation\Request $route_request
* A request object.
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
* A RouteMatch object.
* @param array $replacedTitles
* A array replaced titles.
*
* @return string|null
* Either the current title string or NULL if unable to determine it.
*/
public function getTitleString(Request $route_request, RouteMatchInterface $route_match, array $replacedTitles) {
try {
$title = $this->titleResolver
->getTitle($route_request, $route_match
->getRouteObject());
} catch (\InvalidArgumentException $exception) {
$title = NULL;
}
$this
->applyTitleReplacement($title, $replacedTitles);
// Title resolver only returns title if route defines a _title or
// _title_callback but some core routes like node.edit or block_content.edit
// uses $main_content['#title'] to set a title. Add an special case to set a
// title for {entity_type_id}.{operation} when it's possible.
if (NULL === $title && ($entityForm = $route_match
->getRouteObject()
->getDefault('_entity_form'))) {
$entityFormParts = explode('.', $entityForm);
if (2 === count($entityFormParts)) {
$entity_type_id = $entityFormParts[0];
$operation = $entityFormParts[1];
// Operations that can be used as a title: add, edit or delete.
if (in_array($operation, [
'add',
'edit',
'delete',
])) {
$title = $operation;
}
elseif (in_array($operation, [
'default',
'view',
'preview',
])) {
if ($entity = $route_match
->getParameter($entity_type_id)) {
if (is_object($entity)) {
if (method_exists($entity, 'getTitle')) {
$title = $entity
->getTitle();
}
elseif (method_exists($entity, 'label')) {
$title = $entity
->label();
}
}
}
}
}
}
// If title is object then try to render it.
if ($title instanceof MarkupInterface) {
$title = strip_tags(Html::decodeEntities($title));
}
elseif (is_array($title) && array_key_exists('#markup', $title)) {
// If this render array has #allowed tags use that instead of default.
$tags = array_key_exists('#allowed_tags', $title) ? $title['#allowed_tags'] : NULL;
$title = Html::decodeEntities(Xss::filter($title['#markup'], $tags));
}
if (!is_string($title)) {
return NULL;
}
return $title;
}
/**
* Remove duplicate repeated segments.
*
* @param \Drupal\Core\Link[] $links
* The links.
*
* @return \Drupal\Core\Link[]
* The new links.
*/
protected function removeRepeatedSegments(array $links) {
$newLinks = [];
/** @var \Drupal\Core\Link $last */
$last = NULL;
foreach ($links as $link) {
if (empty($last) || !$this
->linksAreEqual($last, $link)) {
$newLinks[] = $link;
}
$last = $link;
}
return $newLinks;
}
/**
* Compares two breadcrumb links for equality.
*
* @param \Drupal\Core\Link $link1
* The first link.
* @param \Drupal\Core\Link $link2
* The second link.
*
* @return bool
* TRUE if equal, FALSE otherwise.
*/
protected function linksAreEqual(Link $link1, Link $link2) {
$links_equal = TRUE;
if ($link1
->getText() instanceof TranslatableMarkup) {
$link_one_text = (string) $link1
->getText();
}
else {
$link_one_text = $link1
->getText();
}
if ($link2
->getText() instanceof TranslatableMarkup) {
$link_two_text = (string) $link2
->getText();
}
else {
$link_two_text = $link2
->getText();
}
if ($link_one_text != $link_two_text) {
$links_equal = FALSE;
}
if ($link1
->getUrl()
->getInternalPath() != $link2
->getUrl()
->getInternalPath()) {
$links_equal = FALSE;
}
return $links_equal;
}
/**
* 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;
}
// Check to see if the path is actually a redirect, if it is, resolve it to
// its source before we create the request. Strip the starting slash,
// redirect module doesn't include it.
if ($this->moduleHandler
->moduleExists('redirect') && $this->config
->get(EasyBreadcrumbConstants::FOLLOW_REDIRECTS)) {
$redirect_path = $path;
if ($redirect_path[0] === '/') {
$redirect_path = substr($redirect_path, 1);
}
$language_prefix = $this->languageManager
->getCurrentLanguage()
->getId();
if (strpos($redirect_path, "{$language_prefix}/") === 0) {
$redirect_path = substr($redirect_path, strlen("{$language_prefix}/"));
}
$redirects = \Drupal::service('redirect.repository')
->findBySourcePath($redirect_path);
if (!empty($redirects)) {
// Take the first redirect if we have multiple, there should normally
// only be one redirect for a source.
/** @var \Drupal\redirect\Entity\Redirect $redirect */
$redirect = current($redirects);
$path = $redirect
->getRedirectUrl()
->toString();
}
}
// @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;
}
}
/**
* Normalizes a text.
*
* E.g., transforms "about-us" to "About Us" or "About us", according to
* parameters.
*
* @param string $raw_text
* Text to be normalized.
*
* @return string
* Normalized title.
*/
private function normalizeText($raw_text) {
// Transform '-hello--world_javascript-' to 'hello world javascript'.
$normalized_text = str_replace([
'-',
'_',
], ' ', $raw_text);
$normalized_text = trim($normalized_text);
$normalized_text = preg_replace('/\\s{2,}/', ' ', $normalized_text);
// Gets the flag saying the capitalizator mode.
$capitalizator_mode = $this->config
->get(EasyBreadcrumbConstants::CAPITALIZATOR_MODE);
if ($capitalizator_mode === 'ucwords') {
// Transforms the text 'once a time' to 'Once a Time'.
// List of words to be ignored by the capitalizator.
$ignored_words = $this->config
->get(EasyBreadcrumbConstants::CAPITALIZATOR_IGNORED_WORDS);
if (!is_array($ignored_words)) {
$ignored_words = explode(' ', $ignored_words);
}
$words = explode(' ', $normalized_text);
// Transforms the non-ignored words of the segment.
$words[0] = Unicode::ucfirst($words[0]);
$words_quantity = count($words);
for ($i = 1; $i < $words_quantity; ++$i) {
// Transforms this word only if it is not in the list of ignored words.
if (!in_array($words[$i], $ignored_words, TRUE)) {
$words[$i] = Unicode::ucfirst($words[$i]);
}
}
$normalized_text = implode(' ', $words);
}
elseif ($capitalizator_mode === 'ucall') {
// Transforms the text 'once a time' to 'ONCE A TIME'.
$normalized_text = mb_strtoupper($normalized_text);
}
elseif ($capitalizator_mode === 'ucforce') {
// Transforms the text 'once a time' to 'once a TIME'.
// List of words to be forced by the capitalizator.
$forced_words = $this->config
->get(EasyBreadcrumbConstants::CAPITALIZATOR_FORCED_WORDS);
// If case sensitivity is false make all the forced words
// uncapitalized by default.
if ($forced_words && !$this->config
->get(EasyBreadcrumbConstants::CAPITALIZATOR_FORCED_WORDS_CASE_SENSITIVITY)) {
$forced_words = array_map('strtolower', $forced_words);
}
$words = explode(' ', $normalized_text);
// Transforms the non-ignored words of the segment.
if ($this->config
->get(EasyBreadcrumbConstants::CAPITALIZATOR_FORCED_WORDS_FIRST_LETTER)) {
$words[0] = Unicode::ucfirst($words[0]);
}
$words_quantity = count($words);
for ($i = 0; $i < $words_quantity; ++$i) {
// If case sensitivity is false make the compared word uncapitalized in
// order to allow the comparison well.
if (!$this->config
->get(EasyBreadcrumbConstants::CAPITALIZATOR_FORCED_WORDS_CASE_SENSITIVITY)) {
$selected_word = mb_strtolower($words[$i]);
}
else {
$selected_word = $words[$i];
}
// Transforms this word only if it is in the list of forced words.
if (is_array($forced_words) && in_array($selected_word, $forced_words)) {
$words[$i] = mb_strtoupper($selected_word);
}
}
$normalized_text = implode(' ', $words);
}
elseif ($capitalizator_mode === 'ucfirst') {
// Transforms the text 'once a time' to 'Once a time' (ucfirst).
$normalized_text = Unicode::ucfirst($normalized_text);
}
return $normalized_text;
}
/**
* Truncate the title.
*
* @param string $title
* Text/title to be truncated.
*
* @return array|\Drupal\Core\StringTranslation\TranslatableMarkup|false|mixed|string|null
* Return truncated title.
*/
public function truncator(string $title) {
$title = mb_strimwidth($title, 0, $this->config
->get(EasyBreadcrumbConstants::TRUNCATOR_LENGTH), $this->config
->get(EasyBreadcrumbConstants::TRUNCATOR_DOTS) ? '...' : '', 'utf8');
return $title;
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
EasyBreadcrumbBuilder:: |
protected | property | The access manager service. | |
EasyBreadcrumbBuilder:: |
protected | property | Breadcrumb config object. | |
EasyBreadcrumbBuilder:: |
protected | property | The router request context. | |
EasyBreadcrumbBuilder:: |
protected | property | The current path object. | |
EasyBreadcrumbBuilder:: |
protected | property | The current user object. | |
EasyBreadcrumbBuilder:: |
protected | property | The entity repository. | |
EasyBreadcrumbBuilder:: |
protected | property | The entity type manager. | |
EasyBreadcrumbBuilder:: |
protected | property | The language manager. | |
EasyBreadcrumbBuilder:: |
protected | property | The logger service. | |
EasyBreadcrumbBuilder:: |
protected | property | The menu link manager. | |
EasyBreadcrumbBuilder:: |
protected | property | The messenger service. | |
EasyBreadcrumbBuilder:: |
protected | property | The module handler service. | |
EasyBreadcrumbBuilder:: |
protected | property | The path processor service. | |
EasyBreadcrumbBuilder:: |
protected | property | The request stack service. | |
EasyBreadcrumbBuilder:: |
protected | property | The dynamic router service. | |
EasyBreadcrumbBuilder:: |
protected | property | Site config object. | |
EasyBreadcrumbBuilder:: |
protected | property | The title resolver. | |
EasyBreadcrumbBuilder:: |
public | function |
Whether this breadcrumb builder should be used to build the breadcrumb. Overrides BreadcrumbBuilderInterface:: |
|
EasyBreadcrumbBuilder:: |
public | function | Apply title replacements. | |
EasyBreadcrumbBuilder:: |
public | function |
Builds the breadcrumb. Overrides BreadcrumbBuilderInterface:: |
|
EasyBreadcrumbBuilder:: |
public static | function | ||
EasyBreadcrumbBuilder:: |
protected | function | Matches a path in the router. | |
EasyBreadcrumbBuilder:: |
public | function | Get string title for route. | |
EasyBreadcrumbBuilder:: |
protected | function | Compares two breadcrumb links for equality. | |
EasyBreadcrumbBuilder:: |
private | function | Normalizes a text. | |
EasyBreadcrumbBuilder:: |
protected | function | Remove duplicate repeated segments. | |
EasyBreadcrumbBuilder:: |
protected | function | Set request context from passed in $route_match if route is available. | |
EasyBreadcrumbBuilder:: |
public | function | Truncate the title. | |
EasyBreadcrumbBuilder:: |
public | function | Constructs the EasyBreadcrumbBuilder. | |
StringTranslationTrait:: |
protected | property | The string translation service. | 1 |
StringTranslationTrait:: |
protected | function | Formats a string containing a count of items. | |
StringTranslationTrait:: |
protected | function | Returns the number of plurals supported by a given language. | |
StringTranslationTrait:: |
protected | function | Gets the string translation service. | |
StringTranslationTrait:: |
public | function | Sets the string translation service to use. | 2 |
StringTranslationTrait:: |
protected | function | Translates a string to the current language or to a given language. |