class Menu in Helper 8
Provides helpers working with menus and menu links.
Hierarchy
- class \Drupal\helper\Menu
Expanded class hierarchy of Menu
1 string reference to 'Menu'
1 service uses Menu
File
- src/
Menu.php, line 17
Namespace
Drupal\helperView source
class Menu {
/**
* The menu tree.
*
* @var \Drupal\Core\Entity\EntityStorageInterface
*/
protected $menuTree;
/**
* The menu active trail interface.
*
* @var \Drupal\Core\Menu\MenuActiveTrailInterface
*/
protected $menuActiveTrail;
/**
* File constructor.
*
* @param \Drupal\Core\Menu\MenuLinkTreeInterface $menu_tree
* The entity type manager.
* @param \Drupal\Core\Menu\MenuActiveTrailInterface $menu_active_trail
* The active trail service.
*/
public function __construct(MenuLinkTreeInterface $menu_tree, MenuActiveTrailInterface $menu_active_trail) {
$this->menuTree = $menu_tree;
$this->menuActiveTrail = $menu_active_trail;
}
/**
* Builds a render array of a menu and its links.
*
* @param string $menu_name
* The machine name of the menu.
* @param 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.
* @param int $depth
* Number of levels to display, includes the initial level. Zero is
* unlimited depth.
* @param 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.
*
* @see \Drupal\system\Plugin\Block\SystemMenuBlock::build
*
* @return array
* The render array.
*/
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;
}
/**
* Builds a render array of a set of links like a menu.
*
* @param string $menu_name
* The menu name (any value can be provided).
* @param \Drupal\Core\Link[] $links
* An array of links.
*
* @return array
* The render array.
*/
public function buildLinksAsMenu($menu_name, array $links) {
return [
'#theme' => 'menu__' . strtr($menu_name, '-', '_'),
'#menu_name' => $menu_name,
'#items' => $this
->convertLinksToMenuLinks($links),
// Make sure drupal_render() does not re-order the links.
'#sorted' => TRUE,
];
}
/**
* Convert a link field to an array of menu links.
*
* @param \Drupal\Core\Link[] $links
* The links to convert.
*
* @return array
* The menu link items, ready for rendering in a menu.
*/
public function convertLinksToMenuLinks(array $links) {
$menu_links = [];
// Generate a menu-link-style key for each link.
$key_prefix = 'helper_link:';
foreach ($links as $delta => $link) {
$menu_link = $this
->convertLinkToMenuLink($link);
$menu_links[$key_prefix . md5(serialize($menu_link))] = $menu_link;
}
return $menu_links;
}
/**
* Convert a link into a menu link.
*
* @param \Drupal\Core\Link $link
* The link to convert.
*
* @return array
* The menu link, ready for rendering in a menu.
*/
public function convertLinkToMenuLink(Link $link) {
// @todo Should this abstracted to its own formatter for link field types?
return [
'is_expanded' => FALSE,
'is_collapsed' => FALSE,
'in_active_trail' => FALSE,
'attributes' => new Attribute(),
'title' => $link
->getText(),
'url' => $link
->getUrl(),
'below' => [],
// @todo This should be a MenuLinkContent object.
'original_link' => NULL,
];
}
/**
* Builds a render array of a set of links like a menu.
*
* @param string $menu_name
* The menu name (any value can be provided).
* @param \Drupal\Core\Field\FieldItemListInterface $items
* A link field item list.
*
* @return array
* The render array.
*/
public function buildLinkFieldAsMenu($menu_name, FieldItemListInterface $items) {
assert($items
->getFieldDefinition()
->getType() === 'link');
$build = [
'#theme' => 'menu__' . strtr($menu_name, '-', '_'),
'#menu_name' => $menu_name,
'#items' => $this
->convertLinkItemsToMenuLinks($items),
// Make sure drupal_render() does not re-order the links.
'#sorted' => TRUE,
];
$metadata = CacheableMetadata::createFromObject($items
->getEntity());
$metadata
->applyTo($build);
return $build;
}
/**
* Convert a link field to an array of menu links.
*
* @param \Drupal\Core\Field\FieldItemListInterface $items
* The link field items to convert.
*
* @return array
* The menu link items, ready for rendering in a menu.
*/
public function convertLinkItemsToMenuLinks(FieldItemListInterface $items) {
$menu_links = [];
// Generate a menu-link-style key for each link.
$key_prefix = $items
->getEntity()
->getEntityTypeId() . ':' . $items
->getEntity()
->id() . ':' . $items
->getFieldDefinition()
->getName() . ':';
foreach ($items as $delta => $item) {
$link = $this
->convertLinkItemToLink($item);
$menu_links[$key_prefix . $delta] = $this
->convertLinkToMenuLink($link);
}
return $menu_links;
}
/**
* Convert a link field item into a link.
*
* @param \Drupal\link\Plugin\Field\FieldType\LinkItem $item
* The link field item to convert.
*
* @return \Drupal\Core\Link
* The link.
*/
public function convertLinkItemToLink(LinkItem $item) {
// Render the link item using the default formatter, because the title may
// contain tokens.
$item_build = $item
->view();
// Create a link object from the rendered item.
return Link::fromTextAndUrl($item_build['#title'], $item_build['#url']);
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
Menu:: |
protected | property | The menu active trail interface. | |
Menu:: |
protected | property | The menu tree. | |
Menu:: |
public | function | Builds a render array of a set of links like a menu. | |
Menu:: |
public | function | Builds a render array of a set of links like a menu. | |
Menu:: |
public | function | Builds a render array of a menu and its links. | |
Menu:: |
public | function | Convert a link field to an array of menu links. | |
Menu:: |
public | function | Convert a link field item into a link. | |
Menu:: |
public | function | Convert a link field to an array of menu links. | |
Menu:: |
public | function | Convert a link into a menu link. | |
Menu:: |
public | function | File constructor. |