Wenn zwei Module in 'hook_menu' denselben Menüpfad definiert haben, welches wird Drupal auswählen?

14

Beispielsweise definiert "moduleone" den Pfad "admin / hello", der ausgegeben wird 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" definiert den Pfad 'admin / hello', der ausgegeben wird 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;
}

Beide Module haben den 'admin / hello'-Pfad für unterschiedliche Ergebnisse definiert. Wie wählt Drupal mit diesen beiden aktivierten Modulen eines als das andere aus? Wie löst Drupal den Konflikt?

Gilzero
quelle

Antworten:

16

Die aufrufende Funktion hook_menu()ist menu_router_build () , die von menu_rebuild () aufgerufen wird . Es enthält den folgenden Code.

  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);

Wenn zwei Module dieselbe Route definieren, module_implements()überschreibt das letzte Modul in dem von zurückgegebenen Array den von den anderen Modulen definierten Wert.

Der zweite erforderliche Parameter module_implements()ist wie folgt definiert:

$sortStandardmäßig werden die Module nach Gewicht und Dateiname sortiert. Die Einstellungen für diese Option werden in der Modulliste nach TRUEModulnamen sortiert.

Da menu_router_build()der zweite Parameter nicht an übergeben wird menu_implements(), verwendet die Funktion den Standardwert für diesen Parameter. Dies bedeutet, dass die Liste der Module nach Gewicht und Dateiname sortiert ist. Wenn zwei Module das gleiche Gewicht haben, wird in der Liste als erstes Modul das Modul angezeigt, das alphabetisch an erster Stelle steht.

Darüber hinaus kann jede hook_module_implements_alter()Modulimplementierung die Reihenfolge ändern, in der die Hooks aufgerufen werden.

Aus diesem Grund sollten Sie nicht davon ausgehen, dass Sie wissen, in welcher Reihenfolge die Hooks aufgerufen werden.
Wenn der Zweck des Codes darin besteht, die von einem anderen Modul implementierte Route zu ändern, z. B. weil eine Route entfernt werden soll, wenn ein zweites Modul installiert und aktiviert wird, sollte der Code verwendet werden hook_menu_alter(). Wenn Sie versuchen zu verstehen, welches Modul bei Routenkonflikten "gewinnen" würde, würde ich einen solchen Routenkonflikt lieber vermeiden und eine Route definieren, die noch nicht von einem anderen Modul definiert wurde.

Wenn Sie dann implementieren hook_menu_alter()und sicherstellen möchten, dass Ihr Modul zuletzt ausgeführt wird, sollten Sie auch implementieren , um das Modul zu sein, das eine Route effektiv überschreibt hook_module_implements_alter().

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;
  }
}
kiamlaluno
quelle
so klar und hilfreich, danke. Vielen Dank auch für die Erwähnung der Verwendung hook_menu_alter () in diesem Fall.
Gilzero
Was ist, wenn zwei Module denselben Pfad in hook_menu_alter () definieren? gleiche Regeln angewendet?
Gilzero
hook_menu_alter()wird nicht verwendet, um neue Menüs zu definieren, sondern um die vorhandenen zu ändern. Wenn zwei Module dasselbe Menü ändern, bleibt nur die Änderung des Moduls übrig, das zuletzt ausgeführt wurde.
kiamlaluno
4

Welches Modul weightin der systemTabelle einen niedrigeren Wert hat, wird zuerst aufgerufen. weightIn diesem Fall gewinnt das Modul mit dem höheren Wert.

Wenn die Gewichte für zwei (oder mehr) Module gleich sind, gibt es meines Erachtens keine andere bestimmte Reihenfolge als die, die direkt aus der MySQL-Tabelle stammt (ich könnte mich jedoch irren).

Da die Rückgabeergebnisse beim Aufrufen von hook_menunur in einem Array von Menüelementen zusammengefasst werden, kommt es nie zu einem „Konflikt“. Die Ergebnisse späterer Aufrufe von bis hook_menuüberschreiben einfach die Ergebnisse früherer Aufrufe.

Clive
quelle
4
Laut Pro Drupal Development werden Module mit gleichem Gewicht in alphabetischer Reihenfolge nach ihrem Systemnamen aufgerufen.
mpdonadio
2
Was in diesem Buch berichtet wird, ist richtig: Die Liste der Module, die einen Hook implementieren, ist im Allgemeinen nach Gewicht und alphabetisch sortiert. es wäre nicht sortiert werden , wenn module_implements()bekommt FALSEals zweiter Parameter, aber Funktionen wie module_invoke_all()Anrufe mit nur einem Parameter.
kiamlaluno
Mein vorheriger Kommentar ist nicht ganz genau. Was ich in meiner Antwort berichte, ist richtig.
kiamlaluno