[Resolu]hook_menu débutant

Information importante

En raison d'un grand nombre d'inscriptions de spammers sur notre site, polluant sans relache notre forum, nous suspendons la création de compte via le formulaire de "sign up".

Il est néanmoins toujours possible de devenir adhérent•e en faisant la demande sur cette page, rubrique "Inscription" : https://www.drupal.fr/contact


De plus, le forum est désormais "interdit en écriture". Il n'est plus autorisé d'y écrire un sujet/billet/commentaire.

Pour contacter la communauté, merci de rejoindre le slack "drupalfrance".

Si vous voulez contacter le bureau de l'association, utilisez le formulaire disponible ici, ou envoyez-nous un DM sur twitter.

Bonjour,

Je souhaite faire un hook_menu mais j'aurais besoin de quelques renseignements.
Je suis partie d'un exemple du livre pro drupal developpment mais si j'installe ce module, déjà ça ne fonctionne pas, est-ce normal?

(j'ai bien vidé le cache)

Comment indiquer que je veux que mon hook se fasse uniquement dans les liens primaires?

Si la page existe déjà, pour le page callback, je mets le chemin de ma page et non pas le nom d'une fonction?

<?php
function menufun_menu() {
 
// comment tester si mon menu appartient au lien primaire alors je fais mon hook
 
$items['menufun'] = array(
   
'page callback' => 'menufun_hello',
   
'access callback' => TRUE,
   
'type' => MENU_CALLBACK,
  );
 
  return
$items;
}

/**
 * Page callback.
 */
function menufun_hello() {
  return
t('Hello!');
}
?>

Merci de votre aide

Forum : 
Version de Drupal : 

merci Yoran, j'y vois de nouveau un peu plus clair.

En fait, je suis perdue quand à la méthode à utiliser pour faire ce que je veux.

J'ai un type de contenu que j'affiche dans un menu, mais je voudrais que mes liens ne pointent pas sur node/19 mais marque/19 (une view avec argument).

Plusieurs problèmes se posent à moi :
- J'aimerai que les items de menu (pour ce type de contenu uniquement) se génèrent automatiquement sans que l'utilisateur n'est à le placer dans un menu, ni à saisir le chemin à overrider.

Je me mélange les pinceaux avec le hook_menu, hook_menu_alter, hook_menu_link_alter et le hook_link_alter.

Dans l'absolu pour overrider le chemin, quel hook dois-je utiliser, un hook__alter_link ou hook_menu_link_alter?

Quelles solutions s'offrent à moi pour créer ce menu dynamiquement sans intervention de l'utilisateur?

Merci de votre aide

j'ai essayé de faire un hook_form_alter, mais je ne comprends pas ça me dit que la page est inaccessible.

Pourriez-vous m'éclairer, svp,je vais bientôt être chauve

<?php

function menu_marque_menu_alter(&$items) {
 
//peut-on directement mettre le path ou doit-on appeler obligatoirement une fonction?
 
$items['node/19']['page callback'] = 'menu_marque_path';
  unset (
$items['node/19']['file']);
}

function menu_marque_path(){
//comment lui dire que le nouveau path est celui-ci?
 
return('marque/19');
 }

?>

Dans l'absolu c'est le hook_menu_alter qui te permet d'overrider vers quelle callback dirige telle ou telle url. Mais pour cela tu dois utiliser le chemin déclaré par le module; dans ton exemple tu prends 'node/19' mais ça n'existe pas (cf hook_menu du module node); le module node déclare en réalité quelque chose comme 'node/%' ou node/%node'.

En gros le plus simple c'est d'ouvrir le module responsable du chemin que tu souhaites overrider, trouver dans son hook menu l'array qui lui correspond afin d'avoir les infos nécessaires pour le hook_menu_alter.

ok merci, j'ai trouvé dans le module node

<?php
$items
['node/%node'] = array(
   
'title callback' => 'node_page_title',
   
'title arguments' => array(1),
   
'page callback' => 'node_page_view',
   
'page arguments' => array(1),
   
'access callback' => 'node_access',
   
'access arguments' => array('view', 1),
   
'type' => MENU_CALLBACK);


function
node_page_view($node, $cid = NULL) {
 
drupal_set_title(check_plain($node->title));
  return
node_show($node, $cid);
}
?>

Par contre je ne comprends pas où je peux modifier le chemin

En fait j'ai du mal à comprendre ce que tu veux faire donc je ne sais pas comment t'aider :-/
edit : quel intéret de faire mener le lien directement vers la vue ? à quoi te servent les nodes du coup ?

en fait j'ai créé un type de contenu 'marque' à un type de contenu 'vetement'.

Je n'ai pas utilisé la taxonomie, car j'avais besoin d'insérer le logo pour les marques. (je sais qu'il existe un module taxonomy image pour en rajouter, mais si le client me demande d'autres infos sur la marque ça ne fonctionnera plus)

J'ai donc créé un menu qui m'affiche la liste des marques.

Par contre quand on clic sur une marque, je ne veux pas arriver sur la page marque où l'on a le logo mais sur une view m'affichant la liste des vêtements pour cette marque.

D'où mon besoin de rediriger le chemin des marques vers le chemin de ma view avec argument.

a priori ce serait plus une histoire de redirection que d'altérer le menu. Par exemple faire un hook_init du genre :

<?php
monomodule_init
() {
  if(
arg(0) == 'node' && is_numeric(arg(1))){
 
$node = node_load(arg(1));
  if(
$node->type == 'marque'){
   
drupal_goto('marque/'. $node->nid);
    }
  }
}
?>

(edit : la if(arg(0) == 'node') est pas terrible car on ne pourra plus éditer les nodes, à affiner)

ok, merci je commence à voir la lumière (je suis perdue dans les hook_menu, hook_link...), je ne connaissais pas ce hook quelle est sa fonction exacte?

Pour l'édition on peut tester pour voir si on a un 2eme argument ou pas.

Merci sa fonctionne nickel, par contre quand on passe sur le lien, ça met toujours node/nid, ce hook s'applique donc lorsque l'on clique sur le lien pas avant.

Est-il possible de faire afficher le bon lien dans la barre d'état?

"ok, merci je commence à voir la lumière (je suis perdue dans les hook_menu, hook_link...), je ne connaissais pas ce hook quelle est sa fonction exacte?"

heu je ne sais pas :-)
je le mets quand je ne sais pas quel autre hook mettre. normalement on y ajoute les css et js d'un module, et j'ai tendance à m'en servir pour mettre à jour des sessions, récupérer des données $_POST, $_GET mais je ne sais pas si c'est une bonne pratique ou un truc bizarre de faire ça.

Ce n'est peut être pas la manière optimale de faire une redirection, je ne sais pas comment font les autres développeurs pour réaliser cela.

C'est pas une mauvaise manière, en fait c'est la bonne mais faut savoir ce que cela implique. hook_init (et son compère hook_exit) sont le premier (et le dernier) hook invoqué sur un module. En gros, dés que Drupal démarre, et qu'il a chargé les modules activés, il invoque le hook_init de chacun d'eux (idem à la fin de la réponse à la requête avec hook_exit).

On s'est mis à coller les insertions CSS/JS dans ce hook avec Drupal 6 car avec cette version, le hook_menu n'était plus appelé à chaque requête (et c'est mieux ainsi). En Drupal 5, c'était donc dans hook_menu que l'on faisait ces inclusions et hook_init n'était jamais ou presque utilisé.

L'effet de bord de cette "nouvelle" approche est que si un et un seul module activé a un "hook_init", le cache de drupal ne peut plus passer en mode "agressif". Le mode agressif de cache étant celui où aucun module n'est chargé du tout et que tout part du cache directe. Or avec un hook_init qui traine, Drupal considère que ce mode est risqué et n'autorise donc que le mode "normal".

Donc pour les sites à très très gros traffic, on fait la chasse aux modules qui utilisent hook_init :) dans les 99.9% de cas contraire on s'en moque.

Du coup le hook_init est utilisé pour effectuer des tâches de manière non conditionnelle, à chaque réponse de Drupal à une requête. On peut par exemple insérer du JS/CSS, changer dynamiquement le thème pour un site mobile, ou comme tu viens de le faire, opérer une redirection.

Tient, Nyl, une astuce que j'ai découverte récemment :

<?php
monomodule_init
() {
  if(
$node=menu_get_objet()){
     if(
$node->type == 'marque'){
      
drupal_goto('marque/'. $node->nid);
     }
   }
}
?>

Je le trouve bien pratique cette fonction menu_get_object :)

Que teste-t-on avec

if($node=menu_get_objet()){ ?

Merci Yoran pour les précisions sur le hook_init.

Connaitriez-vous un site qui explique les différents hook de manière plus explicite que sur l'api drupal ? (perso quand on débute c'est la misère car la fonction + les paramètres c'est un peu léger, le top ça serait un petit texte expliquant le genre de choses que l'on peut faire, avec des exemples)

Avec menu_get_object tu valides que l'URL représente un objet reconnu par drupal (ici node/XXX renvoie l'object $node de nid XXX). Si cette fonction renvoie "null", cela veut dire que le chemin n'est pas de la forme node/XXX.

La meilleur manière de comprendre les hook est d'utiliser la documentation qui est en anglais. Le truc est de taper dans google le nom du hook (ex. hook_menu) et de cliquer sur "j'ai de la chance" ;-) Fait seulement attention à l'onglet qui doit correspondre à ta version de Drupal.

Merci pour l'astuce, je ne connaissais pas cette fonction, très utile :-)

Si je comprends bien ça peut renvoyer aussi bien un user qu'un node ou que tout autre objet avec lequel une fonction load est associé dans le module qui déclare le hook_menu.

le seul truc qui me chagrine c'est d'utiliser une fonction de type node_load ou celle-ci (qui appelle aussi node_load dans notre cas si je comprends bien) juste pour récupérer un type de node.

Il n'y a pas une fonction plus légère pour charger juste les infos vitales d'un node (titre, type de contenu) sans passer par node load, ou bien faut-il faire soi même la requete sql?

J'ai lu qu'il existait une sorte de cache pour les appels à node_load mais j'ignore son efficacité.

Tu as raison, dans ce cas, ce n'est pas du plus bel effet côté performance. Il y a en effet un cache, mais c'est un cache statique, c'est à dire qui ne dure que pendant le cycle de vie de la page. Donc qui le node_load est perdu lors de la redirection...

Donc garde l'astuce, mais dans ce cas précis, à cause de la redirection, c'est clairement pas un bonne idée, désolé :)

Sinon, juste en passant, je viens de me rendre compte que CCK fait un truc terrible en terme de perfs : il fait un select pour chaque table composant un type de contenu... au lieu de faire un série d'inner joins... Remarque en CCK pour D5, il lui arrivait de faire un par champ, y'a un mieux :)

arf les champs customs avec les CMS c'est rarement léger :-/
Ca me manque de faire mes tables moi mêmes.

Pour ce que tu dis, je ne pense pas que la redirection y change forcément quelque chose puisque d'après ce que tu m'expliques le node a pu éventuellement être mis en cache lors des hooks précédents (je ne connais pas le fonctionnament d'une variable static : ça veut dire qu'elle se conserve au travers de chaque appel de fonction pour la page en cours c'est ça ?) non ?

Non, c'est rarement léger, mais là ça n'aurait pas coûté plus cher à être moins lourd :) D'ailleurs, je viens de trouver un gros TODO dans le code de CCK, qui dit exactement la même chose ;-)

Ce n'est pas la redirection qui change quelque chose en soit, mais sa nature au sein du cycle de création d'une page. En effet, elle se fait dans un hook_init, le plus tôt possible, donc avec un max de chances que rien d'autre n'ai été fait avant (donc pas déjà en cache) et comme cela arrête direct le traitement, on en fait rien après non plus. Car en effet, les variables statiques, c'est pour la page en cours.