tester-1.0.0/src/Plugin/Tester/MenuTester.php
src/Plugin/Tester/MenuTester.php
<?php
namespace Drupal\tester\Plugin\Tester;
use Drupal\tester\Attribute\TesterPlugin;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Component\Plugin\PluginBase;
use Drupal\Core\Menu\MenuLinkTreeInterface;
use Drupal\Core\Menu\MenuTreeParameters;
use Drupal\Core\Routing\RouteNotFoundException;
use Drupal\tester\Plugin\TesterPluginInterface;
use Symfony\Component\Routing\Exception\RouteNotFoundException as SymfonyRouteNotFoundException;
/**
* Defines routes owned by the Menu system.
*/
#[TesterPlugin(
id: 'menu',
)]
class MenuTester extends PluginBase implements TesterPluginInterface {
/**
* The menu link tree service.
*
* @var \Drupal\Core\Menu\MenuLinkTreeInterface
*/
protected $menuTree;
/**
* Constructs a MenuTester object.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Menu\MenuLinkTreeInterface $menu_tree
* The menu link tree service.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, MenuLinkTreeInterface $menu_tree) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->menuTree = $menu_tree;
}
/**
* {@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')
);
}
/**
* {@inheritdoc}
*/
public function urls(array $options) {
$urls = [];
$parameters = new MenuTreeParameters();
// Normalize menu options to array.
$options['menus'] = explode(',', $options['menus']);
foreach ($options['menus'] as $menu) {
$tree = $this->menuTree->load(trim($menu), $parameters);
$manipulators = [
[
'callable' => 'menu.default_tree_manipulators:generateIndexAndSort',
],
];
$tree = $this->menuTree->transform($tree, $manipulators);
$this->buildUrls($tree, $urls);
}
if ($options['limit'] > 0 && count($urls) >= $options['limit']) {
$urls = array_slice($urls, 0, $options['limit']);
}
return $urls;
}
/**
* Creates a recursive URL generator.
*
* Each item in a menu tree may itself be a menu tree, so we loop through
* each one and then check for the presence of a `subtree`.
*
* @param array $tree
* The menu tree.
* @param array $urls
* The array of urls to test.
*/
public function buildUrls($tree, array &$urls) {
foreach ($tree as $element) {
$link = $element->link;
$url = $link->getUrlObject();
if (!$url->isExternal() && $link->isEnabled()) {
try {
$string = $url->toString();
// Ignore any token paths, which break logins.
// And explicitly do not log out.
if (!str_contains($string, '?token=') && !str_contains($string, 'user/logout')) {
$urls[] = $string;
}
}
// @phpstan-ignore-next-line
catch (RouteNotFoundException | SymfonyRouteNotFoundException $e) {
// Skip menu links that reference non-existent routes.
// This can happen with contrib modules like Admin Toolbar Tools
// that create menu links to routes that may not exist.
}
}
if ($element->subtree) {
$this->buildUrls($element->subtree, $urls);
}
}
}
/**
* {@inheritdoc}
*/
public function dependencies() {
return [
'modules' => [
'system',
],
];
}
}
