Если два модуля определили один и тот же путь меню в 'hook_menu', какой из них выберет Drupal?

14

Например, «moduleone» определяет путь «admin / hello», который выводится 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» определяет путь «admin / hello», который выводится 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;
}

Оба модуля определили путь admin / hello для разных результатов. Когда эти два модуля включены, как Drupal выбирает один, а другой? Как Drupal разрешает конфликт?

gilzero
источник

Ответы:

16

Вызываемая функция hook_menu()- menu_router_build () , вызываемая menu_rebuild () . Он содержит следующий код.

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

Если есть два модуля, определяющих один и тот же маршрут, последний модуль в массиве, возвращенном module_implements()функцией, переопределит значение, определенное для других модулей.

Второй требуемый параметр module_implements()определяется как:

$sortПо умолчанию модули упорядочены по весу и имени файла, при настройке этой опции TRUEсписок модулей будет упорядочен по имени модуля.

Поскольку menu_router_build()второй параметр не передается menu_implements(), функция использует значение по умолчанию для этого параметра. Это означает, что список модулей упорядочен по их весу и имени файла; когда два модуля имеют одинаковый вес, первый модуль, который появляется в списке, является первым в алфавитном порядке.

Кроме того, любой реализующий модуль hook_module_implements_alter()может изменить порядок вызова хуков.

По этой причине вы не должны предполагать, что знаете, в каком порядке вызываются хуки.
Если целью кода является изменение маршрута, реализованного другим модулем, например, потому что маршрут должен быть удален при установке и включении второго модуля, следует использовать код hook_menu_alter(). Если вы пытаетесь понять, какой модуль «победит» в случае конфликтов маршрутов, я бы предпочел избежать такого конфликта маршрутов и определить маршрут, который еще не определен из другого модуля.

Если затем вы реализуете hook_menu_alter()и хотите быть уверенным, что ваш модуль выполняется последним, чтобы быть модулем, который эффективно переопределяет маршрут, вы должны также реализовать его 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;
  }
}
киамлалуно
источник
так ясно и полезно, спасибо. также спасибо за упоминание использования hook_menu_alter () в этом случае.
Гильзеро
что если два модуля определяют один и тот же путь в hook_menu_alter ()? применяются те же правила?
Gilzero
hook_menu_alter()используется не для определения новых меню, а для изменения существующих. Если два модуля изменяют одно и то же меню, то изменение, которое сохраняется, является тем из модуля, который выполняется последним.
kiamlaluno
4

Какой из модулей имеет меньшее weightзначение в systemтаблице, будет вызван первым, поэтому weightв этом случае модуль с более высоким значением будет «выигрывать».

Если весовые коэффициенты одинаковы для двух (или более) модулей, я полагаю, что никакого конкретного упорядочения не производится, кроме упорядочения, получаемого непосредственно из таблицы MySQL (хотя я могу ошибаться в этом).

Поскольку возвращаемые результаты вызова hook_menuпросто помещаются в один массив пунктов меню, «конфликт» как таковой никогда не возникнет, результаты последующих вызовов hook_menuпросто переопределят результаты предыдущих вызовов.

Клайв
источник
4
Согласно Pro Drupal Development , модули с одинаковым весом называются в алфавитном порядке по имени их системы.
mpdonadio
2
То, что сообщается в этой книге, верно: список модулей, реализующих хук, обычно сортируется по весу и по алфавиту; он не будет отсортирован, если module_implements()получит в FALSEкачестве второго параметра, но функции, такие как module_invoke_all()вызовы, только с параметром.
kiamlaluno
Мой предыдущий комментарий не совсем точен. То, что я сообщаю в своем ответе, верно.
kiamlaluno