web-dev-qa-db-fra.com

Comment puis-je charger un menu par programme avec un suivi actif défini par une URL fournie?

Travailler sur un site sans tête Drupal, et nous avons rencontré un problème. Nous avons une ressource REST qui renvoie des menus arbitraires par menu-id, mais ils ont toujours "active-trail" défini sur false sur chaque élément de menu.

J'aimerais pouvoir spécifier une URL ou un itinéraire lors de la création du menu et que le chemin actif soit équivalent à ce qu'il serait si le menu était chargé sur cet itinéraire.

Pour le moment, notre solution consiste à parcourir chaque élément de menu jusqu'à ce que nous trouvions celui qui correspond à l'URL fournie, puis à le marquer ainsi que tous ses parents comme "piste active", mais cela semble inutilement lourd et je me demande si il y a une solution plus sensée que nous avons négligée.

Actuellement, nous chargeons des menus comme celui-ci:

$tree = $this->menuTree->load('menu_id', new MenuTreeParameters());

Où $ this-> menuTree est une instance de MenuLinkTree en cours d'instanciation via l'injection de dépendance:

/**
 * {@inheritdoc}
 */
public function __construct(array $configuration, $plugin_id, $plugin_definition, array $serializer_formats, LoggerInterface $logger, MenuLinkTreeInterface $menu_tree, EntityTypeManagerInterface $entity_type_manager, Request $current_request) {
  parent::__construct($configuration, $plugin_id, $plugin_definition, $serializer_formats, $logger);

  $this->menuTree = $menu_tree;
  $this->entityTypeManager = $entity_type_manager;
  $this->request = $current_request;
  $this->alias = $this->request->query->get('alias');
}

/**
 * {@inheritdoc}
 */
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
  return new static(
    $configuration,
    $plugin_id,
    $plugin_definition,
    $container->getParameter('serializer.formats'),
    $container->get('logger.factory')->get('rest'),
    $container->get('menu.link_tree'),
    $container->get('entity_type.manager'),
    $container->get('request_stack')->getCurrentRequest()
  );
}
5
Drif.io

Injectez le menu.active_trail dépendance avec menu.link_tree:

private $activeTrail;

/**
 * {@inheritdoc}
 */
public function __construct(array $configuration, $plugin_id, $plugin_definition, array $serializer_formats, LoggerInterface $logger, MenuLinkTreeInterface $menu_tree, MenuActiveTrailInterface $active_trail, EntityTypeManagerInterface $entity_type_manager, Request $current_request) {
  parent::__construct($configuration, $plugin_id, $plugin_definition, $serializer_formats, $logger);

  $this->menuTree = $menu_tree;
  $this->activeTrail = $active_trail;
  $this->entityTypeManager = $entity_type_manager;
  $this->request = $current_request;
  $this->alias = $this->request->query->get('alias');
}

/**
 * {@inheritdoc}
 */
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
  return new static(
    $configuration,
    $plugin_id,
    $plugin_definition,
    $container->getParameter('serializer.formats'),
    $container->get('logger.factory')->get('rest'),
    $container->get('menu.link_tree'),
    $container->get('menu.active_trail'),
    $container->get('entity_type.manager'),
    $container->get('request_stack')->getCurrentRequest()
  );
}

Maintenant au lieu de:

$tree = $this->menuTree->load('menu_id', new MenuTreeParameters());

obtenez l'ID de piste actif juste avant de créer votre menu et transmettez-le dans le cadre des paramètres:

// Change this to menu machine name.
$menu_id = 'menu_id';

// This should return an array. 
// Array contains menu link uuid's, keyed by the uuid's iirc. 
// For example something like:
//   'menu_link:abcdefg_123' => 'menu_link:abcdefg_123'
$activeTrailIds = $this->activeTrail->getActiveTrailIds($menu_id); 

$params = new MenuTreeParameters();
$params->setActiveTrail($activeTrailIds);
$tree = $this->menuTree->load($menu_id, $params);

Cela devrait vous renvoyer une arborescence de menus avec des pistes actives correctes.

5
Beebee

J'ai également eu ce cas et, comme Drif.io le décrit dans son commentaire à la réponse de Beebee, j'ai dû étendre la classe principale MenuActiveTrail.

Dans mon cas, je l'ai résolu via Patch, mais dans d'autres cas d'utilisation, ce serait probablement une meilleure idée d'étendre la classe et de créer un propre service. Nous utilisons la fonctionnalité via patch dans un module de base où nous ne pouvons pas créer de dépendance à un module personnalisé.

Jusqu'à présent, la fonction getActiveTrailIds ressemblait à ceci:

public function getActiveTrailIds($menu_name) {
  return $this->get($menu_name);
}

J'ai changé de fonction pour accepter une option $route_match paramètre. Cependant, à cause du paramètre, j'ai dû désactiver la mise en cache de la piste active, car lorsqu'un fil d'Ariane normal de la même navigation (principale) est affiché sans le paramètre de correspondance d'itinéraire, il y a un autre résultat.

public function getActiveTrailIds($menu_name,$route_match = null) {
  unset($this->storage[$menu_name]); //disable caching for this case.
  if ($route_match) {
    $this->routeMatch = $route_match;
  }
  return $this->get($menu_name);
}

Maintenant, je peux appeler le service en utilisant

\Drupal::service('menu.active_trail')->getActiveTrailIds('main',$route_match);
1
Florian Müller