두 개의 모듈이 모두 '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은 어떻게 갈등을 해결합니까?

답변:


16

호출하는 함수 hook_menu()menu_rebuild () 에 의해 호출되는 menu_router_build () 입니다. 다음 코드가 포함되어 있습니다.

  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 ()를 언급 해 주셔서 감사합니다.
gilzero

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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.