Comment dois-je implémenter hook_menu ()?

103

Quels sont les principes fondamentaux de la mise en œuvre hook_menu()?

J'aimerais voir les bases abordées dans une seule question, pour éviter d'avoir à répondre sans cesse aux mêmes questions identiques mais différentes.

Letharion
la source

Réponses:

148

Cette information est valable pour Drupal 6 et 7. Dans Drupal 8, hook_menu()a été remplacé par un nouveau système de routage . Ci-dessous, nous mettons en œuvre hook_menu()en trois étapes simples.

La première étape

Créez un module vide en suivant les instructions de la section Création d'un module vide . Dans le code présenté ici, il est supposé que le module s'appelle helloworld .

Deuxième étape

Ajoutez le code suivant au fichier de module.

/**
 * Implements hook_menu().
 */
function helloworld_menu() {
  $items['hello'] = array(
    'title' => 'Hello world!',
    'page callback' => 'helloworld_page',
    'access callback' => TRUE,
  );

  return $items;
}

/**
 * Page callback for /hello.
 */
function helloworld_page() {
  return 'Hello world!';
}

Troisième étape

Activez le module et visitez http://example.com/hello . (Remplacez example.com par le nom de domaine de votre serveur.) Le
message "Hello world!" Devrait s'afficher. C'est ça! Vous avez une hook_menu()implémentation pleinement opérationnelle . Ce qui suit sont divers sujets plus avancés concernant hook_menu(). En particulier, vous voudrez peut-être vous renseigner sur les autorisations, car la page ci-dessus sera accessible à tous.

Arguments

Si vous souhaitez transmettre plus de données au rappel de page, vous pouvez utiliser des arguments de page pour y parvenir. Les arguments de page doivent être un tableau d'arguments à transmettre au rappel de page. Si un entier est utilisé comme argument, il représentera une partie de l'URL, à partir de 0, incrémenté une fois pour chaque barre oblique (/). Dans l'exemple suivant, cela signifie que le 0 sera transformé en "bonjour".

function helloworld_menu() {
  $items['hello'] = array(
    'page callback' => 'helloworld_page',
    'page arguments' => array(0),
  );

  return $items;
}

function helloworld_page($argument1) {
  return $argument1;
}

Les chaînes seront envoyées mot pour mot, donc array(0, 'world')pourraient être utilisées pour sortir hello worldà nouveau.

function helloworld_page($argument1, $argument2) {
  return $argument1 . ' ' . $argument2;
}

Les "caractères génériques" peuvent être utilisés pour accepter des données arbitraires de l'URL.

function helloworld_menu() {
  $items['hello/%'] = array(
    'page callback' => 'helloworld_page',
    'page arguments' => array(1),
  );

  return $items;
}

function helloworld_page($argument1) {
  return $argument1;
}

Visiter bonjour / monde, $argument1sera égal world.

Chargement automatique des arguments

Souvent, un argument d'URL sera le numéro identifiant, par exemple, une entité. Pour éviter la duplication du code qui convertit cet ID en son objet correspondant, Drupal prend en charge le chargement automatique des caractères génériques "nommés". Si un caractère générique nommé est utilisé, Drupal recherchera une fonction portant le même nom que le caractère générique, suffixé par _load. Si une telle fonction est trouvée, elle sera appelée avec la valeur de la valeur dans l'URL, et tout ce qui sera renvoyé par la fonction de chargement sera passé à la page rappel à la place de la valeur d'origine. Comme Drupal a déjà une telle fonction pour charger les nœuds, node_load()nous pouvons obtenir des nœuds chargés automatiquement et passés au rappel de la page.

function helloworld_menu() {
  $items['hello/%node'] = array(
    'page callback' => 'helloworld_page',
    'page arguments' => array(1),
  );

  return $items;
}

function helloworld_page($node) {
  return t('Hello node (ID = !nid)', array('!nid' => $node->nid));
}

Chargement automatique avancé

Parfois, il sera nécessaire d’en charger plusieurs en fonction de plusieurs arguments. Etant donné que seul l'argument nommé est transmis au chargeur par défaut, il est nécessaire d'indiquer explicitement à Drupal quels arguments de charge supplémentaires doivent être transmis au chargeur. Par exemple, pour charger une révision spécifique d'un nœud, il est nécessaire de passer à node_load()un ID de nœud et à un ID de révision. Cela peut être accompli par le code suivant.

function helloworld_menu() {
  $items['hello/%node/revision/%'] = array(
    'page callback' => 'helloworld_page',
    'page arguments' => array(1),
    'load arguments' => array(3),
  );

  return $items;
}

function helloworld_page($node) {
  return t('Hello node (ID = !nid, revision ID = !rid)', array('!nid' => $node->nid, '!rid' => $node->vid));
}

Les permissions

'access callback' => TRUE,Il est nécessaire de rendre l’exemple simple ci-dessus visible, mais c’est loin d’être idéal, car il ne permet aucun contrôle. Toute personne qui essaie de visiter / bonjour aura accès. Le moyen le plus simple de fournir une mesure de contrôle consiste à fournir un rappel d’accès, un peu comme le rappel de page précédent. Le code suivant autorise toujours l'accès à n'importe qui, mais montre comment déplacer la logique vers une fonction appelée au moment de l'accès, permettant ainsi une logique plus complexe.

/**
 * Implements hook_menu().
 */
function helloworld_menu() {
  $items['hello'] = array(
    'page callback' => 'helloworld_page',
    'access callback' => 'helloworld_access',
  );

  return $items;
}

/**
 * Access callback for /hello.
 */
function helloworld_access() {
  return TRUE;
}

Ce n'est pas forcément la meilleure solution, car l'utilisation d'une fonction personnalisée dupliquera souvent inutilement le code. Un meilleur moyen sera, la plupart du temps, à utiliser user_access(). Ensemble, le rappel d'accès, il est possible de définir des arguments d'accès. Il est possible d'exiger que la page soit accessible aux utilisateurs disposant de l' autorisation d' accès aux profils utilisateur avec le code suivant.

/**
 * Implements hook_menu().
 */
function helloworld_menu() {
  $items['hello'] = array(
    'page callback' => 'helloworld_page',
    'access callback' => 'user_access',
    'access arguments' => array('access user profiles'),
  );

  return $items;
}

Comme le rappel d'accès par défaut est user_access, il peut être omis, comme dans le code ci-dessus.

Sujets plus avancés

La hook_menu()documentation officielle fournit beaucoup plus d’informations sur les cas d’utilisation les plus complexes pour le hook.

Letharion
la source
3
Impressionnant! Pour des raisons d'exhaustivité, la titlepropriété est requise pour tous les articles retournés dehook_menu()
Clive
1
Je sais que les docs le disent, mais lorsque j’ai testé D7, ce n’était pas le cas. Je pense que je pourrais l’ajouter au premier exemple, mais je voulais garder les choses au minimum absolu pour que ce soit aussi simple que possible.
Letharion
1
Je dirais que l’ajout d’un titre à une page est l’une des choses minimales que vous voudriez faire avec hook_menu () mais c’est votre message: P Cela vaudrait peut-être la peine de corriger les erreurs de syntaxe (exemples de code 2, 4, 5 & 6), afin que les gens puissent copier et coller
Clive
1
Argh, au départ, j’étais diligent dans l’exécution du code, mais avec le temps, je me suis retrouvé de plus en plus négligé et j’ai commencé à copier-coller. Correction des erreurs de syntaxe, du moins celles que j'ai vues;) Eh bien, vous avez raison de dire qu'il devrait bien sûr y avoir un titre, alors j'en ai ajouté un à l'exemple initial.
Létharion
1
Comment enregistrer un fichier php sur un chemin en utilisant hook_menu? C'est un fichier php écrit personnalisé qui inclut le bootstrap drupal, utilise les variables de session drupal et accepte un argument qui est un identifiant d'utilisateur.
Елин Й.