Active
Project:
Drupal core
Version:
main
Component:
menu system
Priority:
Normal
Category:
Feature request
Assigned:
Unassigned
Reporter:
Created:
19 Sep 2024 at 05:09 UTC
Updated:
19 Sep 2024 at 05:09 UTC
Jump to comment: Most recent
As per #3091246: Allow MenuLinkTree manipulators to be altered there are a number of use cases for altering MenuLinkTree manipulators. Sometimes you just want to provide custom access controls to menu links.
One way to achieve this is to decorate the menu.default_tree_manipulators service. This works pretty well, but it means you need to implement all the public methods, including checkAccess, checkNodeAccess, generateIndexAndSort, and flatten. There is no guarantee that there won't be another method added in the future.
mymodule.services.yml:
services:
Drupal\my_module\Menu\MyModuleMenuLinkTreeManipulators:
decorates: 'menu.default_tree_manipulators'
autowire: true
MyModuleMenuLinkTreeManipulators.php
<?php
declare(strict_types=1);
namespace Drupal\my_module\Menu;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Menu\DefaultMenuLinkTreeManipulators;
use Drupal\Core\Menu\MenuLinkTreeElement;
use Drupal\Core\Session\AccountInterface;
/**
* Decorates the menu.default_tree_manipulators service.
*
* @see \Drupal\Core\Menu\DefaultMenuLinkTreeManipulators
*/
final class MyModuleMenuLinkTreeManipulators {
public function __construct(
protected DefaultMenuLinkTreeManipulators $inner,
protected AccountInterface $account,
) {}
/**
* @see DefaultMenuLinkTreeManipulators::checkAccess()
*/
public function checkAccess(array $tree): array {
$tree = $this->inner->checkAccess($tree);
foreach ($tree as $element) {
$this->menuLinkCheckAccess($element);
}
return $tree;
}
/**
* Custom access check.
*/
protected function menuLinkCheckAccess(MenuLinkTreeElement $element): void {
if (isset($element->access) && $element->access->isForbidden()) {
return;
}
if ($element->link->getPluginId() === 'my_module.custom_menu_link') {
$element->access = AccessResult::allowedIfHasPermission($this->account, 'my module permission');
}
foreach ($element->subtree as $branch) {
$this->menuLinkCheckAccess($branch);
}
}
public function checkNodeAccess(array $tree): array {
return $this->inner->checkNodeAccess($tree);
}
public function generateIndexAndSort(array $tree): array {
return $this->inner->generateIndexAndSort($tree);
}
public function flatten(array $tree): array {
return $this->inner->flatten($tree);
}
}
Is this even viable?
Comments