You are here

protected function MenuLinkTree::buildItems in Drupal 9

Same name and namespace in other branches
  1. 8 core/lib/Drupal/Core/Menu/MenuLinkTree.php \Drupal\Core\Menu\MenuLinkTree::buildItems()
  2. 10 core/lib/Drupal/Core/Menu/MenuLinkTree.php \Drupal\Core\Menu\MenuLinkTree::buildItems()

Builds the #items property for a menu tree's renderable array.

Helper function for ::build().

Parameters

\Drupal\Core\Menu\MenuLinkTreeElement[] $tree: A data structure representing the tree, as returned from MenuLinkTreeInterface::load().

\Drupal\Core\Cache\CacheableMetadata &$tree_access_cacheability: Internal use only. The aggregated cacheability metadata for the access results across the entire tree. Used when rendering the root level.

\Drupal\Core\Cache\CacheableMetadata &$tree_link_cacheability: Internal use only. The aggregated cacheability metadata for the menu links across the entire tree. Used when rendering the root level.

Return value

array The value to use for the #items property of a renderable menu.

Throws

\DomainException

1 call to MenuLinkTree::buildItems()
MenuLinkTree::build in core/lib/Drupal/Core/Menu/MenuLinkTree.php
Builds a renderable array from a menu tree.

File

core/lib/Drupal/Core/Menu/MenuLinkTree.php, line 212

Class

MenuLinkTree
Implements the loading, transforming and rendering of menu link trees.

Namespace

Drupal\Core\Menu

Code

protected function buildItems(array $tree, CacheableMetadata &$tree_access_cacheability, CacheableMetadata &$tree_link_cacheability) {
  $items = [];
  foreach ($tree as $data) {

    /** @var \Drupal\Core\Menu\MenuLinkInterface $link */
    $link = $data->link;

    // Generally we only deal with visible links, but just in case.
    if (!$link
      ->isEnabled()) {
      continue;
    }
    if ($data->access !== NULL && !$data->access instanceof AccessResultInterface) {
      throw new \DomainException('MenuLinkTreeElement::access must be either NULL or an AccessResultInterface object.');
    }

    // Gather the access cacheability of every item in the menu link tree,
    // including inaccessible items. This allows us to render cache the menu
    // tree, yet still automatically vary the rendered menu by the same cache
    // contexts that the access results vary by.
    // However, if $data->access is not an AccessResultInterface object, this
    // will still render the menu link, because this method does not want to
    // require access checking to be able to render a menu tree.
    if ($data->access instanceof AccessResultInterface) {
      $tree_access_cacheability = $tree_access_cacheability
        ->merge(CacheableMetadata::createFromObject($data->access));
    }

    // Gather the cacheability of every item in the menu link tree. Some links
    // may be dynamic: they may have a dynamic text (e.g. a "Hi, <user>" link
    // text, which would vary by 'user' cache context), or a dynamic route
    // name or route parameters.
    $tree_link_cacheability = $tree_link_cacheability
      ->merge(CacheableMetadata::createFromObject($data->link));

    // Only render accessible links.
    if ($data->access instanceof AccessResultInterface && !$data->access
      ->isAllowed()) {
      continue;
    }
    $element = [];

    // Set a variable for the <li> tag. Only set 'expanded' to true if the
    // link also has visible children within the current tree.
    $element['is_expanded'] = FALSE;
    $element['is_collapsed'] = FALSE;
    if ($data->hasChildren && !empty($data->subtree)) {
      $element['is_expanded'] = TRUE;
    }
    elseif ($data->hasChildren) {
      $element['is_collapsed'] = TRUE;
    }

    // Set a helper variable to indicate whether the link is in the active
    // trail.
    $element['in_active_trail'] = FALSE;
    if ($data->inActiveTrail) {
      $element['in_active_trail'] = TRUE;
    }

    // Note: links are rendered in the menu.html.twig template; and they
    // automatically bubble their associated cacheability metadata.
    $element['attributes'] = new Attribute();
    $element['title'] = $link
      ->getTitle();
    $element['url'] = $link
      ->getUrlObject();
    $element['url']
      ->setOption('set_active_class', TRUE);
    $element['below'] = $data->subtree ? $this
      ->buildItems($data->subtree, $tree_access_cacheability, $tree_link_cacheability) : [];
    if (isset($data->options)) {
      $element['url']
        ->setOptions(NestedArray::mergeDeep($element['url']
        ->getOptions(), $data->options));
    }
    $element['original_link'] = $link;

    // Index using the link's unique ID.
    $items[$link
      ->getPluginId()] = $element;
  }
  return $items;
}