diff --git a/src/TwigExtension.php b/src/TwigExtension.php index 1f9fb7e..c604341 100644 --- a/src/TwigExtension.php +++ b/src/TwigExtension.php @@ -4,6 +4,8 @@ namespace Drupal\twig_tweak; use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; +use Drupal\Core\Menu\MenuActiveTrailInterface; +use Drupal\Core\Menu\MenuLinkTreeInterface; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Site\Settings; use Drupal\Core\Utility\Token; @@ -42,6 +44,20 @@ class TwigExtension extends \Twig_Extension { */ protected $routeMatch; + /** + * The menu link tree service. + * + * @var \Drupal\Core\Menu\MenuLinkTreeInterface + */ + protected $menuTree; + + /** + * The active menu trail service. + * + * @var \Drupal\Core\Menu\MenuActiveTrailInterface + */ + protected $menuActiveTrail; + /** * TwigExtension constructor. * @@ -53,12 +69,18 @@ class TwigExtension extends \Twig_Extension { * The configuration factory. * @param \Drupal\Core\Routing\RouteMatchInterface $route_match * The route match. + * @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(EntityTypeManagerInterface $entity_type_manager, Token $token, ConfigFactoryInterface $config_factory, RouteMatchInterface $route_match) { + public function __construct(EntityTypeManagerInterface $entity_type_manager, Token $token, ConfigFactoryInterface $config_factory, RouteMatchInterface $route_match, MenuLinkTreeInterface $menu_tree, MenuActiveTrailInterface $menu_active_trail) { $this->entityTypeManager = $entity_type_manager; $this->token = $token; $this->configFactory = $config_factory; $this->routeMatch = $route_match; + $this->menuTree = $menu_tree; + $this->menuActiveTrail = $menu_active_trail; } /** @@ -71,6 +93,7 @@ class TwigExtension extends \Twig_Extension { new \Twig_SimpleFunction('drupal_token', [$this, 'drupalToken']), new \Twig_SimpleFunction('drupal_entity', [$this, 'drupalEntity']), new \Twig_SimpleFunction('drupal_field', [$this, 'drupalField']), + new \Twig_SimpleFunction('drupal_menu', [$this, 'drupalMenu']), new \Twig_SimpleFunction('drupal_config', [$this, 'drupalConfig']), ]; } @@ -178,6 +201,41 @@ class TwigExtension extends \Twig_Extension { return NULL; } + /** + * Returns the render array for Drupal menu. + * + * @param string $menu_name + * The name of the menu. + * @param int $level + * (optional) Initial menu level. + * @param int $depth + * (optional) Maximum number of menu levels to display. + * + * @return array + * A render array for the menu. + */ + public function drupalMenu($menu_name, $level = 1, $depth = 0) { + $parameters = $this->menuTree->getCurrentRouteMenuTreeParameters($menu_name); + + // Adjust the menu tree parameters based on the block's configuration. + $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 = [ + ['callable' => 'menu.default_tree_manipulators:checkAccess'], + ['callable' => 'menu.default_tree_manipulators:generateIndexAndSort'], + ]; + $tree = $this->menuTree->transform($tree, $manipulators); + return $this->menuTree->build($tree); + } + /** * Gets data from this configuration. * diff --git a/tests/src/Functional/TwigTweakTest.php b/tests/src/Functional/TwigTweakTest.php index b47af1a..e8b63bc 100644 --- a/tests/src/Functional/TwigTweakTest.php +++ b/tests/src/Functional/TwigTweakTest.php @@ -88,6 +88,18 @@ class TwigTweakTest extends BrowserTestBase { $xpath = '//div[@class = "tt-field"]/div[contains(@class, "field--name-body")]/p[. != ""]'; $this->assertByXpath($xpath); + // Test menu (default). + $xpath = '//div[@class = "tt-menu-default"]/ul[@class = "menu"]/li/a[. = "Link 1"]/../ul[@class = "menu"]/li/ul[@class = "menu"]/li/a[. = "Link 3"]'; + $this->assertByXpath($xpath); + + // Test menu (level). + $xpath = '//div[@class = "tt-menu-level"]/ul[@class = "menu"]/li/a[. = "Link 2"]/../ul[@class = "menu"]/li/a[. = "Link 3"]'; + $this->assertByXpath($xpath); + + // Test menu (depth). + $xpath = '//div[@class = "tt-menu-depth"]/ul[@class = "menu"]/li[not(ul)]/a[. = "Link 1"]'; + $this->assertByXpath($xpath); + // Test block. $xpath = '//div[@class = "tt-block"]'; $xpath .= '/div[@id="block-powered-by-drupal"]/span[contains(., "Powered by Drupal")]'; diff --git a/tests/twig_tweak_test/config/install/system.menu.twig-tweak-test.yml b/tests/twig_tweak_test/config/install/system.menu.twig-tweak-test.yml new file mode 100644 index 0000000..54d5301 --- /dev/null +++ b/tests/twig_tweak_test/config/install/system.menu.twig-tweak-test.yml @@ -0,0 +1,7 @@ +langcode: en +status: true +dependencies: {} +id: twig-tweak-test +label: Twig tweak test +description: '' +locked: false diff --git a/tests/twig_tweak_test/templates/twig-tweak-test.html.twig b/tests/twig_tweak_test/templates/twig-tweak-test.html.twig index 2cbaa19..0a7b45f 100644 --- a/tests/twig_tweak_test/templates/twig-tweak-test.html.twig +++ b/tests/twig_tweak_test/templates/twig-tweak-test.html.twig @@ -6,6 +6,9 @@