Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
0.00% |
0 / 1 |
|
0.00% |
0 / 9 |
CRAP | |
0.00% |
0 / 75 |
SystemMenuBlock | |
0.00% |
0 / 1 |
|
0.00% |
0 / 9 |
132 | |
0.00% |
0 / 75 |
__construct | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 4 |
|||
create | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 8 |
|||
blockForm | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 29 |
|||
processMenuLevelParents | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 3 |
|||
blockSubmit | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 3 |
|||
build | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 16 |
|||
defaultConfiguration | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 5 |
|||
getCacheTags | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 4 |
|||
getCacheContexts | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 3 |
<?php | |
/** | |
* @file | |
* Contains \Drupal\system\Plugin\Block\SystemMenuBlock. | |
*/ | |
namespace Drupal\system\Plugin\Block; | |
use Drupal\Core\Block\BlockBase; | |
use Drupal\Core\Cache\Cache; | |
use Drupal\Core\Form\FormStateInterface; | |
use Drupal\Core\Menu\MenuActiveTrailInterface; | |
use Drupal\Core\Menu\MenuLinkTreeInterface; | |
use Drupal\Core\Plugin\ContainerFactoryPluginInterface; | |
use Symfony\Component\DependencyInjection\ContainerInterface; | |
/** | |
* Provides a generic Menu block. | |
* | |
* @Block( | |
* id = "system_menu_block", | |
* admin_label = @Translation("Menu"), | |
* category = @Translation("Menus"), | |
* deriver = "Drupal\system\Plugin\Derivative\SystemMenuBlock" | |
* ) | |
*/ | |
class SystemMenuBlock extends BlockBase implements ContainerFactoryPluginInterface { | |
/** | |
* The menu link tree service. | |
* | |
* @var \Drupal\Core\Menu\MenuLinkTreeInterface | |
*/ | |
protected $menuTree; | |
/** | |
* The active menu trail service. | |
* | |
* @var \Drupal\Core\Menu\MenuActiveTrailInterface | |
*/ | |
protected $menuActiveTrail; | |
/** | |
* Constructs a new SystemMenuBlock. | |
* | |
* @param array $configuration | |
* A configuration array containing information about the plugin instance. | |
* @param string $plugin_id | |
* The plugin_id for the plugin instance. | |
* @param array $plugin_definition | |
* The plugin implementation definition. | |
* @param \Drupal\Core\Menu\MenuLinkTreeInterface $menu_tree | |
* The menu tree service. | |
* @param \Drupal\Core\Menu\MenuActiveTrailInterface $menu_active_trail | |
* The active menu trail service. | |
*/ | |
public function __construct(array $configuration, $plugin_id, $plugin_definition, MenuLinkTreeInterface $menu_tree, MenuActiveTrailInterface $menu_active_trail) { | |
parent::__construct($configuration, $plugin_id, $plugin_definition); | |
$this->menuTree = $menu_tree; | |
$this->menuActiveTrail = $menu_active_trail; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { | |
return new static( | |
$configuration, | |
$plugin_id, | |
$plugin_definition, | |
$container->get('menu.link_tree'), | |
$container->get('menu.active_trail') | |
); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function blockForm($form, FormStateInterface $form_state) { | |
$config = $this->configuration; | |
$defaults = $this->defaultConfiguration(); | |
$form['menu_levels'] = array( | |
'#type' => 'details', | |
'#title' => $this->t('Menu levels'), | |
// Open if not set to defaults. | |
'#open' => $defaults['level'] !== $config['level'] || $defaults['depth'] !== $config['depth'], | |
'#process' => [[get_class(), 'processMenuLevelParents']], | |
); | |
$options = range(0, $this->menuTree->maxDepth()); | |
unset($options[0]); | |
$form['menu_levels']['level'] = array( | |
'#type' => 'select', | |
'#title' => $this->t('Initial menu level'), | |
'#default_value' => $config['level'], | |
'#options' => $options, | |
'#description' => $this->t('The menu will only be visible if the menu item for the current page is at or below the selected starting level. Select level 1 to always keep this menu visible.'), | |
'#required' => TRUE, | |
); | |
$options[0] = $this->t('Unlimited'); | |
$form['menu_levels']['depth'] = array( | |
'#type' => 'select', | |
'#title' => $this->t('Maximum number of menu levels to display'), | |
'#default_value' => $config['depth'], | |
'#options' => $options, | |
'#description' => $this->t('The maximum number of menu levels to show, starting from the initial menu level. For example: with an initial level 2 and a maximum number of 3, menu levels 2, 3 and 4 can be displayed.'), | |
'#required' => TRUE, | |
); | |
return $form; | |
} | |
/** | |
* Form API callback: Processes the menu_levels field element. | |
* | |
* Adjusts the #parents of menu_levels to save its children at the top level. | |
*/ | |
public static function processMenuLevelParents(&$element, FormStateInterface $form_state, &$complete_form) { | |
array_pop($element['#parents']); | |
return $element; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function blockSubmit($form, FormStateInterface $form_state) { | |
$this->configuration['level'] = $form_state->getValue('level'); | |
$this->configuration['depth'] = $form_state->getValue('depth'); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function build() { | |
$menu_name = $this->getDerivativeId(); | |
$parameters = $this->menuTree->getCurrentRouteMenuTreeParameters($menu_name); | |
// Adjust the menu tree parameters based on the block's configuration. | |
$level = $this->configuration['level']; | |
$depth = $this->configuration['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())); | |
} | |
$tree = $this->menuTree->load($menu_name, $parameters); | |
$manipulators = array( | |
array('callable' => 'menu.default_tree_manipulators:checkAccess'), | |
array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'), | |
); | |
$tree = $this->menuTree->transform($tree, $manipulators); | |
return $this->menuTree->build($tree); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function defaultConfiguration() { | |
return [ | |
'level' => 1, | |
'depth' => 0, | |
]; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getCacheTags() { | |
// Even when the menu block 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 block must also be re-rendered for that user, because maybe a menu | |
// link that is accessible for that user has been added. | |
$cache_tags = parent::getCacheTags(); | |
$cache_tags[] = 'config:system.menu.' . $this->getDerivativeId(); | |
return $cache_tags; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getCacheContexts() { | |
// ::build() uses MenuLinkTreeInterface::getCurrentRouteMenuTreeParameters() | |
// to generate menu tree parameters, and those take the active menu trail | |
// into account. Therefore, 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. | |
$menu_name = $this->getDerivativeId(); | |
return Cache::mergeContexts(parent::getCacheContexts(), ['route.menu_active_trails:' . $menu_name]); | |
} | |
} |