123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194 |
- <?php
- namespace Drupal\Core\Menu;
- use Drupal\Core\Cache\CacheableMetadata;
- use Drupal\Core\Entity\EntityManagerInterface;
- use Drupal\Component\Utility\Unicode;
- use Drupal\Core\StringTranslation\StringTranslationTrait;
- use Drupal\Core\StringTranslation\TranslationInterface;
- /**
- * Default implementation of the menu parent form selector service.
- *
- * The form selector is a list of all appropriate menu links.
- */
- class MenuParentFormSelector implements MenuParentFormSelectorInterface {
- use StringTranslationTrait;
- /**
- * The menu link tree service.
- *
- * @var \Drupal\Core\Menu\MenuLinkTreeInterface
- */
- protected $menuLinkTree;
- /**
- * The entity manager.
- *
- * @var \Drupal\Core\Entity\EntityManagerInterface
- */
- protected $entityManager;
- /**
- * Constructs a \Drupal\Core\Menu\MenuParentFormSelector
- *
- * @param \Drupal\Core\Menu\MenuLinkTreeInterface $menu_link_tree
- * The menu link tree service.
- * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
- * The entity manager.
- * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
- * The string translation service.
- */
- public function __construct(MenuLinkTreeInterface $menu_link_tree, EntityManagerInterface $entity_manager, TranslationInterface $string_translation) {
- $this->menuLinkTree = $menu_link_tree;
- $this->entityManager = $entity_manager;
- $this->stringTranslation = $string_translation;
- }
- /**
- * {@inheritdoc}
- */
- public function getParentSelectOptions($id = '', array $menus = NULL, CacheableMetadata &$cacheability = NULL) {
- if (!isset($menus)) {
- $menus = $this->getMenuOptions();
- }
- $options = [];
- $depth_limit = $this->getParentDepthLimit($id);
- foreach ($menus as $menu_name => $menu_title) {
- $options[$menu_name . ':'] = '<' . $menu_title . '>';
- $parameters = new MenuTreeParameters();
- $parameters->setMaxDepth($depth_limit);
- $tree = $this->menuLinkTree->load($menu_name, $parameters);
- $manipulators = [
- ['callable' => 'menu.default_tree_manipulators:checkNodeAccess'],
- ['callable' => 'menu.default_tree_manipulators:checkAccess'],
- ['callable' => 'menu.default_tree_manipulators:generateIndexAndSort'],
- ];
- $tree = $this->menuLinkTree->transform($tree, $manipulators);
- $this->parentSelectOptionsTreeWalk($tree, $menu_name, '--', $options, $id, $depth_limit, $cacheability);
- }
- return $options;
- }
- /**
- * {@inheritdoc}
- */
- public function parentSelectElement($menu_parent, $id = '', array $menus = NULL) {
- $options_cacheability = new CacheableMetadata();
- $options = $this->getParentSelectOptions($id, $menus, $options_cacheability);
- // If no options were found, there is nothing to select.
- if ($options) {
- $element = [
- '#type' => 'select',
- '#options' => $options,
- ];
- if (!isset($options[$menu_parent])) {
- // The requested menu parent cannot be found in the menu anymore. Try
- // setting it to the top level in the current menu.
- list($menu_name, $parent) = explode(':', $menu_parent, 2);
- $menu_parent = $menu_name . ':';
- }
- if (isset($options[$menu_parent])) {
- // Only provide the default value if it is valid among the options.
- $element += ['#default_value' => $menu_parent];
- }
- $options_cacheability->applyTo($element);
- return $element;
- }
- return [];
- }
- /**
- * Returns the maximum depth of the possible parents of the menu link.
- *
- * @param string $id
- * The menu link plugin ID or an empty value for a new link.
- *
- * @return int
- * The depth related to the depth of the given menu link.
- */
- protected function getParentDepthLimit($id) {
- if ($id) {
- $limit = $this->menuLinkTree->maxDepth() - $this->menuLinkTree->getSubtreeHeight($id);
- }
- else {
- $limit = $this->menuLinkTree->maxDepth() - 1;
- }
- return $limit;
- }
- /**
- * Iterates over all items in the tree to prepare the parents select options.
- *
- * @param \Drupal\Core\Menu\MenuLinkTreeElement[] $tree
- * The menu tree.
- * @param string $menu_name
- * The menu name.
- * @param string $indent
- * The indentation string used for the label.
- * @param array $options
- * The select options.
- * @param string $exclude
- * An excluded menu link.
- * @param int $depth_limit
- * The maximum depth of menu links considered for the select options.
- * @param \Drupal\Core\Cache\CacheableMetadata|null &$cacheability
- * The object to add cacheability metadata to, if not NULL.
- */
- protected function parentSelectOptionsTreeWalk(array $tree, $menu_name, $indent, array &$options, $exclude, $depth_limit, CacheableMetadata &$cacheability = NULL) {
- foreach ($tree as $element) {
- if ($element->depth > $depth_limit) {
- // Don't iterate through any links on this level.
- break;
- }
- // Collect the cacheability metadata of the access result, as well as the
- // link.
- if ($cacheability) {
- $cacheability = $cacheability
- ->merge(CacheableMetadata::createFromObject($element->access))
- ->merge(CacheableMetadata::createFromObject($element->link));
- }
- // Only show accessible links.
- if (!$element->access->isAllowed()) {
- continue;
- }
- $link = $element->link;
- if ($link->getPluginId() != $exclude) {
- $title = $indent . ' ' . Unicode::truncate($link->getTitle(), 30, TRUE, FALSE);
- if (!$link->isEnabled()) {
- $title .= ' (' . $this->t('disabled') . ')';
- }
- $options[$menu_name . ':' . $link->getPluginId()] = $title;
- if (!empty($element->subtree)) {
- $this->parentSelectOptionsTreeWalk($element->subtree, $menu_name, $indent . '--', $options, $exclude, $depth_limit, $cacheability);
- }
- }
- }
- }
- /**
- * Gets a list of menu names for use as options.
- *
- * @param array $menu_names
- * (optional) Array of menu names to limit the options, or NULL to load all.
- *
- * @return array
- * Keys are menu names (ids) values are the menu labels.
- */
- protected function getMenuOptions(array $menu_names = NULL) {
- $menus = $this->entityManager->getStorage('menu')->loadMultiple($menu_names);
- $options = [];
- /** @var \Drupal\system\MenuInterface[] $menus */
- foreach ($menus as $menu) {
- $options[$menu->id()] = $menu->label();
- }
- return $options;
- }
- }
|