You are here

MenuSelectTreeBuilder.php in Menu Select 8

Same filename and directory in other branches
  1. 2.0.x src/MenuSelectTreeBuilder.php

Namespace

Drupal\menu_select

File

src/MenuSelectTreeBuilder.php
View source
<?php

namespace Drupal\menu_select;

use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\Menu\MenuLinkInterface;
use Drupal\Core\Menu\MenuLinkTreeInterface;
use Drupal\Core\Menu\MenuTreeParameters;

/**
 * A service for building out the menu trees used in menu select.
 */
class MenuSelectTreeBuilder implements MenuSelectTreeBuilderInterface {

  /**
   * An array of manipulators for the menu tree.
   *
   * @var array
   */
  protected $manipulators = [
    // Use the same manipulators as cores default select list.
    [
      'callable' => 'menu.default_tree_manipulators:checkNodeAccess',
    ],
    [
      'callable' => 'menu.default_tree_manipulators:checkAccess',
    ],
    [
      'callable' => 'menu.default_tree_manipulators:generateIndexAndSort',
    ],
  ];

  /**
   * The menu tree service.
   *
   * @var \Drupal\Core\Menu\MenuLinkTreeInterface
   */
  protected $menuTree;

  /**
   * MenuSelectTreeBuilder constructor.
   */
  public function __construct(MenuLinkTreeInterface $menuTree) {
    $this->menuTree = $menuTree;
  }

  /**
   * {@inheritdoc}
   */
  public function loadMenuTree($menu_name, $max_depth) {
    $parameters = new MenuTreeParameters();
    $parameters
      ->setMaxDepth($max_depth);
    $tree = $this->menuTree
      ->load($menu_name, $parameters);
    return $this->menuTree
      ->transform($tree, $this->manipulators);
  }

  /**
   * {@inheritdoc}
   */
  public function buildRenderedMenu(array $menu_tree, $menu_id, $menu_label, $current_link_id) {
    $menu_key = $this
      ->getMenuKey($menu_id);
    $items[$menu_key] = [
      'data' => $this
        ->generateMenuLink($menu_label, $this
        ->getMenuKey($menu_id)),
    ];
    if (!empty($menu_tree)) {
      $items[$menu_key]['children'] = $this
        ->buildNestedMenu($menu_tree, $menu_id, $current_link_id);
    }
    $build = [
      '#theme' => 'item_list',
      '#list_type' => 'ul',
      '#wrapper_attributes' => [
        'class' => [
          'menu-select-menu-hierarchy',
          'js-menu-select-menu-hierarchy',
        ],
      ],
      '#attributes' => [
        'class' => [
          'menu-select-menu-level',
          'js-menu-select-menu-level',
        ],
      ],
      '#items' => $items,
    ];
    return $build;
  }

  /**
   * Function to generate an array of the full menu.
   *
   * Output keys of each menu link id to it's link title.
   *
   * @param array $menu_tree
   *   Array of the menu tree.
   * @param string $menu_id
   *   The menu ID.
   * @param string $current_link_id
   *   The current link ID.
   *
   * @return mixed
   *   The menu structure.
   */
  protected function buildNestedMenu(array $menu_tree, $menu_id, $current_link_id) {
    $nested_menu = [];
    foreach ($menu_tree as $data) {

      // Exclude the current link ID from becoming a parent of itself.
      if ($current_link_id === $data->link
        ->getPluginId()) {
        continue;
      }
      $menu_key = $this
        ->getMenuKey($menu_id, $data->link);
      $nested_menu[$menu_key]['data'] = $this
        ->generateLink($data->link, $menu_key);
      if (!empty($data->subtree)) {
        $nested_menu[$menu_key]['children'] = $this
          ->buildNestedMenu($data->subtree, $menu_id, $current_link_id);
      }
    }
    return $nested_menu;
  }

  /**
   * Generates a link for an item in the menu tree.
   *
   * @param \Drupal\Core\Menu\MenuLinkInterface $link
   *   The menu link.
   * @param string $menu_key
   *   The menu key of the link.
   *
   * @return array
   *   The renderable array for a link.
   */
  protected function generateLink(MenuLinkInterface $link, $menu_key) {
    return [
      // Use a string of markup for the link, since it is much faster than using
      // renderable arrays and link objects for large menus.
      '#markup' => new FormattableMarkup('<a data-mkey="@mkey" class="menu-select-menu-link js-menu-select-menu-link" href="#menu-select-parent-menu">@title</a>', [
        '@title' => $link
          ->getTitle(),
        '@mkey' => $menu_key,
      ]),
    ];
  }

  /**
   * Generates a link for menu items in the tree.
   *
   * @param string $menu_label
   *   The menu label.
   * @param string $menu_key
   *   The menu key of the link.
   *
   * @return array
   *   The renderable array for a link.
   */
  protected function generateMenuLink($menu_label, $menu_key) {
    return [
      '#markup' => new FormattableMarkup('<a data-mkey="@mkey" class="menu-select-menu-link js-menu-select-menu-link" href="#menu-select-parent-menu">@title</a>', [
        '@title' => sprintf('%s (%s)', $menu_label, t('menu')),
        '@mkey' => $menu_key,
      ]),
    ];
  }

  /**
   * Get the menu key, the combination of the menu and menu link plugin ID.
   *
   * @param string $menu_id
   *   The menu ID.
   * @param \Drupal\Core\Menu\MenuLinkInterface $link
   *   (Optional) The link.
   *
   * @return string
   *   The menu key.
   */
  protected function getMenuKey($menu_id, MenuLinkInterface $link = NULL) {
    return sprintf('%s:%s', $menu_id, $link ? $link
      ->getPluginId() : '');
  }

}

Classes

Namesort descending Description
MenuSelectTreeBuilder A service for building out the menu trees used in menu select.