Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
1099 connectés 

  FORUM HardWare.fr
  Programmation
  PHP

  [Résolu] Hiérarchie de menus : besoin de conseils

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

[Résolu] Hiérarchie de menus : besoin de conseils

n°1597914
ZeBix
edit > preview
Posté le 09-08-2007 à 18:03:46  profilanswer
 

Bonjour tous,
 
J'ai un petit souci en PHP que je vais essayer de vous décrire ici, car je n'arrive pas à trouver une solution satisfaisante :  
 
Je m'occupe de la remouture d'un site Intranet prévu pour 2000 utilisateurs à peu près. La presque entièreté du site est gérée de manière dynamique. Ainsi, pour mes "onglets de navigation", je vais chercher dans une table "menu" (identifiée par "ID" et qui contient notamment un champ "parent" qui est une référence interne vers "ID" ), tous les éléments du menu qui n'ont pas de parent (parent = '0').
 
Au moment où je clique sur un des liens ainsi générés, je dois afficher tous les sous-menu, c'est-à-dire du niveau 1, qui ont comme parent l'ID du niveau 0 que je viens de cliquer.
 
Exemple :  
+- Menu ID=1 ; parent = 0
....+-> Menu ID=4, parent = 1
....+-> Menu ID=5, parent = 1
+- Menu ID=8 ; parent = 0
....+-> Menu ID=10, parent = 8
....+-> Menu ID=17, parent = 8
 
Je clique sur le premier lien, j'arrive sur index.php?id=1 . Le menu secondaire s'affiche, qui me propose les menu ID 4 et 5. Je clique sur le 5, je me retrouve sur index.php?id=5. Jusque là tout est normal et ça fonctionne du reste très bien.
 
Je ne suis pas techniquement limité et je peux avoir une infinité de niveaux en profondeur.
 
Mais maintenant arrive le problème: le niveau 0 étant mon "top menu", il est en réalité constitué d'une liste (<ul> ) formatée en CSS de sorte à se présenter sous forme de "boutons" (mais ce bien toujours des liens). Quand un menu est "actif", il change de couleur, classique.
 
Je check cela tout simplement (je tente de simplifier mon code au max : )

Code :
  1. // Je passe dans une boucler tous les éléments de niveau 0,  
  2. // qui sont correctement stockés (ID et label) via une requête dans le tableau arrayZero[]
  3. echo "<li ".($_GET['id']==$arrayZero['id']?"class='active'":"" ).">
  4. <a href='index.php?id=".$arrayZero['id']."'>".arrayZero['label']."</a></li>";
  5. // "li.active" est la classe CSS qui formate le lien en apparence d'un bouton d'une autre couleur

Tout fonctionne à merveille pour le niveau 0.
 
MAIS évidemment, si je clique par exemple sur le Menu ID 10 (fils du 8), eh bien bien sûr le Menu ID 8 n'est plus en class "active" (puisque le code n'identifiera plus du tout le ID 8 dans l'URL... ) !
 
J'ai trouvé plusieurs manières de contourner ce problème, mais aucune ne me plaît :  
 
- La première, la plus évidente: aller voir qui est l'aïeul de l'item en cours.  Mais c'est ultra lourd : Si je suis dans un niveau 5, cela veut dire que je dois faire 5 requêtes successives (X est le parent de Y, qui est le parent de Z, etc. jusqu'à ce que parent=0 ), juste pour avoir l'affichage que je veux! Cela ne me plaît pas.
- Mettre le niveau 0 en variable $_GET du genre le lien ne va pas vers index.php?id=10 mais vers index.php?level0=8&id=10 ... pas très heureux, et au moment où je construis tous mes liens, je dois taper le niveau en dur ou aller le chercher par une requête, ce qui est un peu lourd (surtout quand le document ID 8 peut très bien être déplacé comme fils du 1 par après).
- J'ai pensé mettre en session une variable de type $_SESSION['level0'], qui ne changerait que si l'on change de niveau 0. Pas mauvaise idée, si ce n'est que, dans l'ordre chronologique, au moment où je dois choisir si le <li> est de classe "active" ou pas, la seule info que j'ai c'est l' "id" qui se trouve en $_GET via mon URL. Or, changer une variable de $_SESSION en fonction du click devrait donc se faire AU MOMENT du click, par exemple avec une fonction JavaScript style onClick. Or, client-side technology oblige, JS ne peut pas intervenir sur les variables de session.
- Construire une sorte de table dynamique qui reprend pour chaque page, quel que soit son niveau, quel est son parent de niveau 0 ... Cela implique d'une manière ou d'une autre que cette table doit être mise à jour à toute modif qui est effectuée, ou alors via un cron, mais c'est vraiment pas élégant ...
 
Bref, je suis un peu perdu. Dans quelques CMS que j'ai analysés, j'ai remarqué que le "active menu tab" n'était pas supporté partout, je suppose donc que ce n'est pas une "issue" si facile ..  L'exemple le plus frappent étant Drupal, qui est pourtant bien coté .. Eh bien regardez les tabs en haut, cliquez dessus : pas de changement de style quand vous en avez sélectionné un ...  Spip, quant à lui, gère ça un peu à la bourrine en appelant tous les documents du menu "fr" par un nom qui comment par "fr_" .. mouais dans le genre flexibilité on a vu mieux (je dois pouvoir bouger les documents à tout moment).
 
Après un peu de googling la seule chose que j'ai trouvé résiderait dans l'utilisation d'une technologie asynchrone du style AJAX. Mais je ne connais pas encore bien cela et ne veux pas me lancer là-dedans pour le moment, et il me semble du reste que ce problème ne doit pourtant pas être si original et doit pouvoir se résoudre en client-server traditionnel, non ?  
 
Est-ce que quelqu'un a une piste de comment réaliser ce que je veux, sans que ce soit un rouleau compresseur de lourdeurs pour la DB / la mémoire de mon serveur ?  
 
Merci d'avance pour toute aide  :jap:

Message cité 1 fois
Message édité par ZeBix le 10-08-2007 à 16:14:40
mood
Publicité
Posté le 09-08-2007 à 18:03:46  profilanswer
 

n°1598106
durkheim
Posté le 10-08-2007 à 11:48:29  profilanswer
 

Citation :

Or, client-side technology oblige, JS ne peut pas intervenir sur les variables de session.

 

Si, avec un appel Ajax. C'est tout simple, tu mets dans un coin ce code:

 
Code :
  1. function connectURL(url)
  2. {
  3. // le navigateur est Firefox ou IE
  4. if (window.XMLHttpRequest)
  5. objXHR = new XMLHttpRequest();
  6. else
  7. {
  8. if (window.ActiveXObject)
  9. objXHR = new ActiveXObject("Microsoft.XMLHTTP" );
  10. }
  11. else
  12. return false;
  13. objXHR.open("GET",url,false);
  14. objXHR.send(null);
  15. if (objXHR.readyState == 4)
  16. return objXHR.responseText;
  17. else
  18. return false;
  19. }
 

Puis dans lévénement onclick de ton lien tu appelles cette fonction avec l'url d'une page php qui modifie les variables de session, du style:

 
Code :
  1. onclick="connectURL('modifierSession.php?level0=1')";
 

Puis dans la page php tu récupères les paramètres et voilou. Je sais que tu ne voulais pas utiliser ça, mais je ne peux pas t'être plus utile, alors je me suis dit, autant essayer.


Message édité par durkheim le 10-08-2007 à 11:50:12
n°1598125
omega2
Posté le 10-08-2007 à 12:34:19  profilanswer
 

Si le menu est inclus dans toutes les pages, alors, au moment de la génération du menu de la page, il suffit que tu donnes une classe aux éléments qui doivent avoir un style différent (ça sert entre autre à ça les "class=" de l'html) et que tu mettes une règle css pour les éléments de la liste qui appartiennent à cette règle.
 
Ca me semble plus simple que de partir avec de l'ajax (qui nécessite d'une part que tu créé un script spécial pour récupérer les données et que d'autre part le javascript soit activé) ou de se torturer l'esprit pour pondre une fonction javascript récursive qui modifierait les propriétés de certains éléments.

n°1598177
durkheim
Posté le 10-08-2007 à 14:16:45  profilanswer
 

Oui, en effet ^^

n°1598200
ZeBix
edit &gt; preview
Posté le 10-08-2007 à 14:42:27  profilanswer
 

@Durkheim : bien que la solution que tu proposes ne semble effectivement pas trop mortelle à mettre en place, je ne comprends pas dans ce code où se trouve la mise en session du level 0 ..  
 
@omega2 : Oui le menu est inclus dans toutes les pages.
Pour savoir de manière dynamique quels sont les éléments qui doivent avoir un style différent, je dois effectuer un test tel que celui dont je link le code dans mon premier post ...  et donc on retombe dans le même souci ..  
ou alors j'ai pas bien compris ce que tu proposes .. tu pourrais développer avec un exemple stp ? ;)
 
Merci à vous deux pour vos réponses en tout cas !

n°1598202
flo850
moi je
Posté le 10-08-2007 à 14:46:24  profilanswer
 

ZeBix a écrit :


- La première, la plus évidente: aller voir qui est l'aïeul de l'item en cours.  Mais c'est ultra lourd : Si je suis dans un niveau 5, cela veut dire que je dois faire 5 requêtes successives (X est le parent de Y, qui est le parent de Z, etc. jusqu'à ce que parent=0 ), juste pour avoir l'affichage que je veux! Cela ne me plaît pas.


 
c'est la solution la plus couramment utilisé
 
et tu peux accelerer  en gardant en cache la structure du site en session par exemple

n°1598206
durkheim
Posté le 10-08-2007 à 14:53:48  profilanswer
 

ZeBix a écrit :

@Durkheim : bien que la solution que tu proposes ne semble effectivement pas trop mortelle à mettre en place, je ne comprends pas dans ce code où se trouve la mise en session du level 0 ..  
 


Bah franchement j'ai pas tout compris à fond. Je te donnais juste un exemple d'appel d'une page php en asynchrone, au cas où ça te donne des idées. Ca permettrait de charger tes menus dynamiquement par exemple (en charger le code au fur et à mesure du déroulement du menu) ou d'appeler une page php qui change des variables de session ou tout ce que peut faire une page php.

n°1598269
omega2
Posté le 10-08-2007 à 15:53:24  profilanswer
 

zebix > Si ta fameuse solution est un "index.php?level0=8&id=10" alors ça n'a rien à voir avec ce dont je te parle. Sans rentrer à fond dans les détails, t'as en gros trois façons de résoudre assez simplement ton problème sans lancer pleins de requêtes vers la base de donnée :
1 ) Tu fais un tableau en php dans lequel tu vas empiler les numéros des id.
Pour le remplir, tu parcours un premier coup la liste des éléments du menu.
Pour chaque élément, si tu tombes sur un élément dont le fils n'est pas le dernier de la liste, tu dépiles (t'enlève le dernier élément du tableau) les éléments un par un jusqu'à tomber sur son père.
Une fois son père trouvé, tu rajoutes l'id de l'élément actuel.
Si tu viens de traiter l'élément du menu demandé par le visiteur tu t'arrêtes là. Si t'es arrivé à la fin de ta liste sans l'avoir trouvé, tu vide le tableau.  
Ensuite, il ne te reste plus qu'a créer ton menu en utilisant ce tableau pour savoir lesquels doivent être affiché différemment.
 
2) tu fais un tableau multidimensionnel pour stocker l'arborescence du menu. Ensuite avec une fonction récursive, tu parcours ce tableau (en appellant la fonction à chaque fois qu'un élément à des descendants) . Quand la fonction trouve la fonction recherché, elle retourne "TRUE". Si elle ne trouve rien et qu'elle n'a pas de descendant elle retourne "FALSE". Si elle a des descendants, elle retourne "TRUE" si l'un d'eux à retourné "TRUE" sinon elle retourne "FALSE". Grâce à ça, tu peux savoir si un élément est à afficher comme s'il était sélectionné ou non. Evidement, il faut le noter quelque part au fur et à mesure et se servir ensuite de cette info quand tu génères le code html.
 
3) si tu programmes en objet et que tu fais un objet par élément du menu avec une référence "objet pére" et une référence "objet fils" dans tes objets, alors dès que t'as trouvé le bon élément, il te suffit de regarder qui est son père et de remonter ainsi jusqu'à la racine du menu (en notant au fur et à mesure que ce sont des éléments a afficher différemment). Ensuite, quand tu transformeras tes objets en éléments d'affichage, tu n'auras plus à chercher les descendants de chaque élément pour savoir comment l'afficher.
 
 
Moi, c'est comme ça que je vois la solution.

n°1598284
ZeBix
edit &gt; preview
Posté le 10-08-2007 à 16:14:22  profilanswer
 

@omega2 :  

Citation :

Si ta fameuse solution est un "index.php?level0=8&id=10"


Non justement, je voudrais éviter cela :)
 
A part ça je pense que je vois ta solution, j'ai dû utiliser cela dans le passé lors de mes cours de C++ et de logique, mais il y a déjà quelques années hihihi :)  ça a l'air performant en termes de logique mais comme justement ça fait un peu longtemps, j'ai du mal au niveau de la réalisation en code ...  
 
En tout cas là je viens de réussir à mettre en place la solution Ajax de durkheim, ça marche à merveille !  
 
La page appelée par la fonction connectURL("lapage.php?ID_Menu=<IDdumenuencours>" ) contient juste :  

Code :
  1. session_start(); // je l'avais oublié en premier lieu et ça marchait pas lol ...  
  2. $_SESSION['ID_menu']=$_GET['ID_menu'];


 
Et je check au moment de l'affichage du menu 0 si $_SESSION["ID_menu"] est égal à celui en cours, si oui je change le style, c'est vraiment ce que je voulais
 
Merci beaucoup à tous pour votre aide !
 
Case closed !


Message édité par ZeBix le 10-08-2007 à 16:18:04
n°1598323
durkheim
Posté le 10-08-2007 à 16:45:12  profilanswer
 

Ravi d'avoir pu t'aider, ça me fait vraiment plaisir.
Le we s'annonce bien ^^


Message édité par durkheim le 10-08-2007 à 16:45:41

Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  PHP

  [Résolu] Hiérarchie de menus : besoin de conseils

 

Sujets relatifs
erreur dans un programme simple (resolu)Histoire de package [Resolu]
[Résolu] position d'un div tout en bas d'une pageDifférence entre membre dans et hors __init__ [RESOLU]
Résolu - Arrayliste, exemple COMPLET[résolu] CSS zoom limité à 30 images ?
Tri de réponses chiffre/caractère [resolu][Résolu][MYSQL] lister les doublons + rapidement
Résolu 
Plus de sujets relatifs à : [Résolu] Hiérarchie de menus : besoin de conseils


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR