Jika dua modul keduanya mendefinisikan jalur menu yang sama di 'hook_menu', yang mana Drupal akan pilih?

14

Sebagai contoh, "moduleone" mendefinisikan path 'admin / hello', yang hasilnya 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" mendefinisikan path 'admin / hello', yang hasilnya 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;
}

Kedua modul mendefinisikan jalur 'admin / halo' untuk hasil yang berbeda. Dengan dua modul ini diaktifkan, bagaimana cara Drupal memilih satu dari yang lain? Bagaimana Drupal menyelesaikan konflik?

gilzero
sumber

Jawaban:

16

Fungsi hook_menu()yang dipanggil adalah menu_router_build () , dipanggil oleh menu_rebuild () . Ini berisi kode berikut.

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

Jika ada dua modul yang mendefinisikan rute yang sama, modul terakhir dalam array yang dikembalikan oleh module_implements()akan menimpa nilai yang ditentukan dari modul lainnya.

Parameter kedua yang dibutuhkan oleh module_implements()didefinisikan sebagai:

$sortSecara default, modul dipesan berdasarkan berat dan nama file, pengaturan opsi ini TRUE, daftar modul akan dipesan berdasarkan nama modul.

Karena menu_router_build()tidak meneruskan parameter kedua menu_implements(), fungsi menggunakan nilai default untuk parameter itu. Ini berarti daftar modul diurutkan berdasarkan berat dan nama file; ketika dua modul memiliki bobot yang sama, modul pertama yang muncul dalam daftar adalah yang memiliki urutan abjad terlebih dahulu.

Selanjutnya, setiap implementasi modul hook_module_implements_alter()dapat mengubah urutan kait dipanggil.

Untuk alasan ini, Anda tidak boleh berasumsi tahu di mana urutan kait dipanggil.
Jika tujuan kode adalah mengubah rute yang diterapkan oleh modul lain, misalnya karena rute harus dihapus ketika modul kedua diinstal dan diaktifkan, kode tersebut harus digunakan hook_menu_alter(). Jika Anda mencoba memahami modul mana yang akan "menang" dalam kasus konflik rute, saya lebih suka menghindari konflik rute tersebut, dan menentukan rute yang belum ditentukan dari modul lain.

Jika kemudian Anda menerapkan hook_menu_alter(), dan Anda ingin memastikan modul Anda dieksekusi terakhir, untuk menjadi modul yang secara efektif menimpa rute, Anda harus menerapkan hook_module_implements_alter()juga.

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
sumber
sangat jelas dan bermanfaat, terima kasih. juga terima kasih telah menyebutkan penggunaan hook_menu_alter () dalam kasus ini.
gilzero
bagaimana jika dua modul mendefinisikan jalur yang sama di hook_menu_alter ()? aturan yang sama diterapkan?
gilzero
hook_menu_alter()tidak digunakan untuk menentukan menu baru, tetapi untuk mengubah yang sudah ada. Jika dua modul mengubah menu yang sama, perubahan yang bertahan adalah yang dari modul yang dieksekusi untuk yang terakhir.
kiamlaluno
4

Modul mana pun yang memiliki weightnilai lebih rendah dalam systemtabel akan dipanggil pertama, sehingga modul dengan nilai lebih tinggi weightakan 'menang' dalam kasus ini.

Jika bobotnya sama untuk dua (atau lebih) modul, saya yakin tidak ada pemesanan khusus yang dilakukan selain pemesanan yang datang langsung dari tabel MySQL (saya bisa salah tentang itu).

Karena hasil pengembalian dari pemanggilan hook_menuhanya dimasukkan ke dalam array tunggal dari item menu tidak akan pernah ada 'konflik' seperti itu, hasil dari panggilan kemudian hook_menuhanya akan menimpa mereka dari panggilan sebelumnya.

Clive
sumber
4
Menurut Pro Drupal Development , modul dengan bobot yang sama disebut dalam urutan abjad dengan nama sistem mereka.
mpdonadio
2
Apa yang dilaporkan oleh buku itu benar: Daftar modul yang menerapkan pengait pada umumnya diurutkan berdasarkan berat dan menurut abjad; itu tidak akan diurutkan jika module_implements()mendapat FALSEsebagai parameter kedua, tetapi fungsi seperti module_invoke_all()memanggilnya hanya dengan parameter.
kiamlaluno
Komentar saya sebelumnya tidak sepenuhnya tepat. Apa yang saya laporkan dalam jawaban saya benar.
kiamlaluno