You are here

public function MenuBasedBreadcrumbBuilder::build in Menu Breadcrumb 8

Same name and namespace in other branches
  1. 2.0.x src/MenuBasedBreadcrumbBuilder.php \Drupal\menu_breadcrumb\MenuBasedBreadcrumbBuilder::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/MenuBasedBreadcrumbBuilder.php, line 283

Class

MenuBasedBreadcrumbBuilder

Namespace

Drupal\menu_breadcrumb

Code

public function build(RouteMatchInterface $route_match) {
  $breadcrumb = new Breadcrumb();

  // Breadcrumbs accumulate in this array, with lowest index being the root
  // (i.e., the reverse of the assigned breadcrumb trail):
  $links = [];

  // (https://www.drupal.org/docs/develop/standards/coding-standards#array)
  //
  if ($this->languageManager
    ->isMultilingual()) {
    $breadcrumb
      ->addCacheContexts([
      'languages:language_content',
    ]);
  }

  // Changing the <front> page will invalidate any breadcrumb generated here:
  $site_config = $this->configFactory
    ->get('system.site');
  $breadcrumb
    ->addCacheableDependency($site_config);

  // Changing any module settings will invalidate the breadcrumb:
  $breadcrumb
    ->addCacheableDependency($this->config);

  // Changing the active trail or URL, of either the current path or the
  // taxonomy-attached path, on this menu will invalidate this breadcrumb:
  $breadcrumb
    ->addCacheContexts([
    'route.menu_active_trails:' . $this->menuName,
  ]);
  $breadcrumb
    ->addCacheContexts([
    'url.path',
  ]);

  // Generate basic breadcrumb trail from active trail.
  // Keep same link ordering as Menu Breadcrumb (so also reverses menu trail)
  foreach (array_reverse($this->menuTrail) as $id) {
    $plugin = $this->menuLinkManager
      ->createInstance($id);

    // Skip items that have an empty URL if the option is set.
    if ($this->config
      ->get('exclude_empty_url') && empty($plugin
      ->getUrlObject()
      ->toString())) {
      continue;
    }

    // Skip items that are disabled in the menu if the option is set.
    if ($this->config
      ->get('exclude_disabled_menu_items') && !$plugin
      ->isEnabled()) {
      continue;
    }

    // Stop items when the first url matching occurs.
    if ($this->config
      ->get('stop_on_first_match') && $plugin
      ->getUrlObject()
      ->toString() == Url::fromRoute('<current>')
      ->toString()) {
      break;
    }
    $links[] = Link::fromTextAndUrl($plugin
      ->getTitle(), $plugin
      ->getUrlObject());
    $breadcrumb
      ->addCacheableDependency($plugin);

    // In the last line, MenuLinkContent plugin is not providing cache tags.
    // Until this is fixed in core add the tags here:
    if ($plugin instanceof MenuLinkContent) {
      $uuid = $plugin
        ->getDerivativeId();
      $entities = $this->entityTypeManager
        ->getStorage('menu_link_content')
        ->loadByProperties([
        'uuid' => $uuid,
      ]);
      if ($entity = reset($entities)) {
        $breadcrumb
          ->addCacheableDependency($entity);
      }
    }
  }
  $this
    ->addMissingCurrentPage($links, $route_match);

  // Create a breadcrumb for <front> which may be either added or replaced:
  $langcode = $this->contentLanguage;
  $label = $this->config
    ->get('front_title') ? $this->configFactory
    ->get('system.site')
    ->get('name') : $this
    ->t('Home', [], [
    'langcode' => $langcode,
  ]);

  // (https://www.drupal.org/docs/develop/standards/coding-standards#array)
  $home_link = Link::createFromRoute($label, '<front>');

  // The first link from the menu trail, being the root, may be the
  // <front> so first compare those two routes to see if they are identical.
  // (Though in general a link deeper in the menu could be <front>, in that
  // case it's arguable that the node-based pathname would be preferred.)
  $front_page = $site_config
    ->get('page.front');
  $front_url = Url::fromUri("internal:{$front_page}");
  $first_url = $links[0]
    ->getUrl();

  // If options are set to remove <front>, strip off that link, otherwise
  // replace it with a breadcrumb named according to option settings:
  if ($first_url
    ->isRouted() && $front_url
    ->isRouted() && $front_url
    ->getRouteName() === $first_url
    ->getRouteName() && $front_url
    ->getRouteParameters() === $first_url
    ->getRouteParameters()) {

    // According to the confusion hopefully cleared up in issue 2754521, the
    // sense of "remove_home" is slightly different than in Menu Breadcrumb:
    // we remove any match with <front> rather than replacing it.
    if ($this->config
      ->get('remove_home')) {
      array_shift($links);
    }
    elseif ($this->config
      ->get('front_title') != 2) {
      $links[0] = $home_link;
    }
  }
  else {

    // If trail *doesn't* begin with the home page, add it if that option set.
    if ($this->config
      ->get('add_home')) {
      array_unshift($links, $home_link);
    }
  }
  if (!empty($links)) {
    $page_type = $this->taxonomyAttachment ? 'member_page' : 'current_page';

    // Display the last item of the breadcrumbs trail as the options indicate.

    /** @var \Drupal\Core\Link $current */
    $current = array_pop($links);
    if ($this->config
      ->get('append_' . $page_type)) {
      if (!$this->config
        ->get($page_type . '_as_link')) {
        $current
          ->setUrl(new Url('<none>'));
      }
      array_push($links, $current);
    }
  }
  return $breadcrumb
    ->setLinks($links);
}