You are here

public function Menu::buildMenu in Helper 8

Builds a render array of a menu and its links.

Parameters

string $menu_name: The machine name of the menu.

int $level: Initial visibility level. The menu is only visible if the menu item for the current page is at this level or below it. Use level 1 to always display this menu.

int $depth: Number of levels to display, includes the initial level. Zero is unlimited depth.

bool $expand_all_items: Override the option found on each menu link used for expanding children and instead display the whole menu tree as expanded.

Return value

array The render array.

See also

\Drupal\system\Plugin\Block\SystemMenuBlock::build

File

src/Menu.php, line 67

Class

Menu
Provides helpers working with menus and menu links.

Namespace

Drupal\helper

Code

public function buildMenu($menu_name, $level = 1, $depth = 0, $expand_all_items = FALSE) {
  if ($expand_all_items) {
    $parameters = new MenuTreeParameters();
    $active_trail = $this->menuActiveTrail
      ->getActiveTrailIds($menu_name);
    $parameters
      ->setActiveTrail($active_trail);
  }
  else {
    $parameters = $this->menuTree
      ->getCurrentRouteMenuTreeParameters($menu_name);
  }

  // Adjust the menu tree parameters based on the level and depth.
  $parameters
    ->setMinDepth($level);

  // When the depth is configured to zero, there is no depth limit. When depth
  // is non-zero, it indicates the number of levels that must be displayed.
  // Hence this is a relative depth that we must convert to an actual
  // (absolute) depth, that may never exceed the maximum depth.
  if ($depth > 0) {
    $parameters
      ->setMaxDepth(min($level + $depth - 1, $this->menuTree
      ->maxDepth()));
  }

  // For menu blocks with start level greater than 1, only show menu items
  // from the current active trail. Adjust the root according to the current
  // position in the menu in order to determine if we can show the subtree.
  $do_tree_build = TRUE;
  if ($level > 1) {
    if (count($parameters->activeTrail) >= $level) {

      // Active trail array is child-first. Reverse it, and pull the new menu
      // root based on the parent of the configured start level.
      $menu_trail_ids = array_reverse(array_values($parameters->activeTrail));
      $menu_root = $menu_trail_ids[$level - 1];
      $parameters
        ->setRoot($menu_root)
        ->setMinDepth(1);
      if ($depth > 0) {
        $parameters
          ->setMaxDepth(min($level - 1 + $depth - 1, $this->menuTree
          ->maxDepth()));
      }
    }
    else {
      $do_tree_build = FALSE;
    }
  }
  if ($do_tree_build) {
    $tree = $this->menuTree
      ->load($menu_name, $parameters);
    $manipulators = [
      [
        'callable' => 'menu.default_tree_manipulators:checkAccess',
      ],
      [
        'callable' => 'menu.default_tree_manipulators:generateIndexAndSort',
      ],
    ];
    $tree = $this->menuTree
      ->transform($tree, $manipulators);
    $build = $this->menuTree
      ->build($tree);
  }

  // Even when the menu renders to the empty string for a user, we want the
  // cache tag for this menu to be set: whenever the menu is changed, this
  // menu output must also be re-rendered for that user, because maybe a menu
  // link that is accessible for that user has been added.
  if (empty($build['#items'])) {
    $build['#cache']['tags'][] = 'config:system.menu.' . $menu_name;
  }

  // We must vary the rendered menu by the active trail of the rendered menu
  // Additional cache contexts, e.g. those that determine link text or
  // accessibility of a menu, will be bubbled automatically.
  $build['#cache']['contexts'][] = 'route.menu_active_trails:' . $menu_name;
  return $build;
}