Se due moduli hanno entrambi definito lo stesso percorso di menu in 'hook_menu', quale Drupal sceglierà?


14

Ad esempio, "moduleone" definisce il percorso 'admin / hello', quale output print_moduleone_stuff().

/**
 * Implements hook_menu()
 */
function moduleone_menu() {
  $items['admin/hello'] = array(
    'title' => 'Module One Hello World',
    'page callback' => print_moduleone_stuff,
  );
  return $items;
}

"moduletwo" definisce il percorso 'admin / hello', che produce print_moduletwo_stuff().

/**
 * Implements hook_menu()
 */
function moduletwo_menu() {
  $items['admin/hello'] = array(
    'title' => 'Module Two Hello World',
    'page callback' => print_moduletwo_stuff,
  );
  return $items;
}

Entrambi i moduli hanno definito il percorso 'admin / hello' per risultati diversi. Con questi due moduli abilitati, in che modo Drupal seleziona uno rispetto all'altro? In che modo Drupal risolve il conflitto?

Risposte:


16

La funzione che invoca hook_menu()è menu_router_build () , chiamata da menu_rebuild () . Contiene il seguente codice.

  foreach (module_implements('menu') as $module) {
    $router_items = call_user_func($module . '_menu');
    if (isset($router_items) && is_array($router_items)) {
      foreach (array_keys($router_items) as $path) {
        $router_items[$path]['module'] = $module;
      }
      $callbacks = array_merge($callbacks, $router_items);
    }
  }
  // Alter the menu as defined in modules, keys are like user/%user.
  drupal_alter('menu', $callbacks);

Se esistono due moduli che definiscono la stessa route, l'ultimo modulo dell'array restituito module_implements()sovrascriverà il valore definito dagli altri moduli.

Il secondo parametro richiesto da module_implements()è definito come:

$sortPer impostazione predefinita, i moduli sono ordinati in base al peso e al nome file, le impostazioni su questa opzione TRUE, l'elenco dei moduli saranno ordinati in base al nome del modulo.

Poiché menu_router_build()non passa il secondo parametro a menu_implements(), la funzione utilizza il valore predefinito per quel parametro. Ciò significa che l'elenco dei moduli è ordinato in base al loro peso e nome file; quando due moduli hanno lo stesso peso, il primo modulo che appare nell'elenco è quello che viene in ordine alfabetico per primo.

Inoltre, qualsiasi implementazione del modulo hook_module_implements_alter()può modificare l'ordine di invocazione degli hook.

Per questo motivo, non si deve supporre di sapere in quale ordine vengono richiamati gli hook.
Se lo scopo del codice sta modificando la route implementata da un altro modulo, ad esempio perché una route dovrebbe essere rimossa quando un secondo modulo è installato e abilitato, il codice dovrebbe usare hook_menu_alter(). Se stai cercando di capire quale modulo "vincerebbe" in caso di conflitti di rotta, preferirei evitare tale conflitto di rotta e definire una rotta che non è già definita da un altro modulo.

Se poi stai implementando hook_menu_alter(), e vuoi essere sicuro che il tuo modulo sia eseguito per ultimo, per essere il modulo che ha effettivamente la precedenza su una route, dovresti implementarlo hook_module_implements_alter()anche tu .

function mymodule_module_implements_alter(&$implementations, $hook) {
  if ($hook == 'menu_alter') {
    // Move mymodule_menu_alter() to the end of the list. module_implements()
    // iterates through $implementations with a foreach loop which PHP iterates
    // in the order that the items were added, so to move an item to the end of
    // the array, we remove it and then add it.
    $group = $implementations['mymodule'];
    unset($implementations['mymodule']);
    $implementations['mymodule'] = $group;
  }
}

così chiaro e utile, grazie. anche grazie per aver menzionato l'uso hook_menu_alter () in questo caso.
Gilzero,

cosa succede se due moduli definiscono lo stesso percorso in hook_menu_alter ()? stesse regole applicate?
Gilzero,

hook_menu_alter()non viene utilizzato per definire nuovi menu, ma per modificare quelli esistenti. Se due moduli modificano lo stesso menu, l'alterazione che sopravvive è quella del modulo che viene eseguito per ultimo.
kiamlaluno

4

Qualunque modulo abbia un weightvalore più basso nella systemtabella verrà chiamato per primo, quindi il modulo con il weightvalore più alto "vincerà" in questo caso.

Se i pesi sono gli stessi per due (o più) moduli credo che non sia stato fatto alcun ordine specifico oltre all'ordinamento che proviene direttamente dalla tabella MySQL (potrei sbagliarmi su questo però).

Poiché i risultati di ritorno dall'invocazione di hook_menuvengono semplicemente inseriti in una singola matrice di voci di menu, non si verificherà mai un "conflitto" in quanto tale, i risultati delle chiamate successive hook_menusostituiranno semplicemente quelli delle chiamate precedenti.


4
Secondo Pro Drupal Development , i moduli con lo stesso peso sono chiamati in ordine alfabetico in base al nome del loro sistema.
mpdonadio

2
Ciò che è riportato da quel libro è corretto: l'elenco dei moduli che implementano un gancio è generalmente ordinato in base al peso e in ordine alfabetico; non verrebbe ordinato se module_implements()ottiene FALSEcome secondo parametro, ma funziona come lo module_invoke_all()chiama con un solo parametro.
kiamlaluno

Il mio commento precedente non è del tutto esatto. Quello che riporto nella mia risposta è corretto.
kiamlaluno
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.