Bonjour,

J'essaie de condenser un maxium le menu de navigation d'un site boostrap que je suis en train de créer. C'est un menu horizontal, déroulant et je voudrais réduire les lignes de code avant d'en faire un include pour le mettre sur toutes les pages du site.

J'ai regardé beaucoup de tutos sur ce sujet mais vu que je n'ai que des notions de php, je ne comprends pas tout. Après avoir essayé de passer par deux tables liées (une pour les éléments du menu et une pour les intitules des sous-menus) j'ai finalement opté pour une table commune après avoir vu un tuto qui parlait de la gestion des parents-enfants dans une même table.

Bien évidemment, mon code ne fonctionne pas correctement : l'arborescence est en pagaille, les niveaux sont mélangés et les classes ne sont pas du tout appliquées (je me retrouve avec une liste à puces au lieu d'avoir des blocs inline).

Voici ma table :

(le 0 de la colonne "Parent" indique les intitulés de chaque menu, le 1, les sous-menus)

ID  Parent Nom URL
1   0 Accueil accueil.php
2   0 Notre entreprise  entreprise.php
3   1 Pr&eacutesentation    entreprise.php
4   1 Recrutement entreprise.php
5   0 Nos produits produits.php
6   1 Par cat&eacutegorie   produits.php
7   1 Par occasion produits.php
8   0 Nos services services.php
9   1 Pr&eacutesentation    services.php
10  1 Services entreprises  services.php
11  0 Nos coordonn&eacutees contact.php
12  1 Notre adresse contact.php
13  1 &Eacutecrivez-nous    contact.php
14  0 Ateliers ateliers.php

Mon code :

<?php

$bdd = new PDO('mysql:host=localhost; dbname=fleuriste','root','root');
$query='SELECT * FROM test ORDER BY Parent';

$result = $bdd->query($query);

while($row = $result->fetch()){

    $categories] = array(
        'parent_id' =>$row'Parent'],
        'categorie_id' =>$row'ID'],
        'categorie_nom'=>$row'Nom'],
        'categorie_url'=>$row'URL']
        );
    }
function show_menu($parent,$niveau,$array){
    $html ='';

    $niveau_precedent = 0;

    if(!$niveau && !$niveau_precedent) $html .='<ul class=\"navbar-collapse collapse list-inline\">';

    foreach($array as $noeud){

        if($parent == $noeud'parent_id']){

        if($niveau_precedent<$niveau) $html .='<li class=\"li-inline dropdown\"><a href="#" class=\"dropdown-toggle\" data-toggle=\"dropdown\">' .$noeud'categorie_nom']. '</a><ul class=\"dropdown-menu\">';
            $html .= '<li><a href=\"?categorie='. $noeud'categorie_url'] .'\">' .$noeud'categorie_nom'] . '</a>';
            $niveau_precedent = $niveau;
            $html .= show_menu($noeud'categorie_id'],($niveau + 1), $array);

    }
}

    if(($niveau_precedent == $niveau) && ($niveau_precedent !=0)) $html .='</ul></li>';

    else if ($niveau_precedent=$niveau) $html .='</ul>';

    else $html .='</li>';

    return $html;

}
?>

Si quelqu'un a une idée ça m'aiderait énormément. Merci d'avance !

7 réponses


Attilette
Auteur
Réponse acceptée

Finalement, vos encouragements m'ont porté chance :D Je suis revenue sur la structure de deux tables liées et j'ai trouvé un bout de code dans un tuto et il fonctionne. Voici les codes, ça pourra peut-être servir à d'autres noobs comme moi :)

ID CHAPITRE URL
1 Accueil accueil.php
2 Notre entreprise entreprise.php
3 Nos produits produits.php
4 Nos services services.php
5 Nos coordonn&eacutees contact.php
6 Ateliers ateliers.php

ID ID_menu SOUS_MENU URL
1 1 accueil.php
2 2 Pr&eacutesentation entreprise.php
3 2 Recrutement entreprise.php
4 3 Par type produits.php
5 3 Par occasion produits.php
6 4 Pr&eacutesentation services.php
7 4 Services entreprises services.php
8 5 Notre adresse contact.php
9 5 &Eacutecrivez-nous contact.php
10 6 ateliers.php

L'appel de la base :

<?php

$pdo = new PDO('mysql:host=localhost;dbname=fleuriste','root','root');
$query1 = 'SELECT * FROM menu ORDER BY ID ASC';
$stmt = $pdo->prepare($query1);
$stmt->execute();

?>

Le code dans le corps du document html :

<ul class="navbar-collapse collapse list-inline">
        <?php
         while($row = $stmt->fetch(PDO::FETCH_OBJ)){
             $query2 = 'SELECT * FROM submenu WHERE ID_menu=:ID';
             $sub_stmt = $pdo->prepare($query2);
             $sub_stmt -> bindParam(':ID', $row->ID, PDO::PARAM_INT);
             $sub_stmt ->execute();
        ?>

            <li class="li-inline dropdown"><a href="<?php echo $row->URL;?>" class="dropdown-toggle" data-toggle="dropdown"><?php echo $row->CHAPITRE;?></a>

        <?php if($sub_stmt->rowCount()){ ?>

            <ul class="dropdown-menu">

            <?php
            while($sub_row = $sub_stmt->fetch(PDO::FETCH_OBJ)){ ?>   
                <li><a href="<?php echo $sub_row->URL;?>"><?php echo $sub_row->SOUS_MENU; ?></a></li>

            <?php } ?>

            </ul>

        <?php } ?>

        </li>
        <?php } ?>
        </ul>

Encore merci à vous deux pour votre bienveillance, ce n'était pas le cas sur d'autres forums ...

salut,
j'avais plancher sur projet du même type, il n'est pas parfait et complètement terminer mais il est fonctionnel

menu via sql

Pour décrire le tableau utilisé:
id: clé primaire mysql
colone: nom du menu déroulant ou unique
colone_id, sa position de gauche à droite
colone mod: simple indique un bouton sans ouverture de menu, multi indique une ouverteure de menu, dep indiquela dépendance à un menu
position: position de bas en haut
nom: nom du sous menu
lien:....
type: href pour des lien url, onclick pour des lien onclick js ,divider pour mettre des espacements.
les autres colonnes ne sont pas fonctionnel.

le code suivant n'est pas optimisé, mais il tourne rond.

<nav class="navbar navbar-inverse" role="navigation">
    <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
        <ul class="nav navbar-nav">
<?php
$data = $DBPDO1->prepare("SELECT DISTINCT (colone) FROM site_menu");
$ncn=count(($data->execute()));
$data = $DBPDO1->prepare("SELECT DISTINCT (colone_id) FROM site_menu");
$nci=count(($data->execute()));
$test=1;
if ($ncn!=$nci) {echo "<pre> erreur dans la rentré des menus. Différence entre le nombre de colones et le nombre d'appelations</pre><br>";}
else
    {
        $data = $DBPDO1->prepare("SELECT * FROM site_menu ORDER BY colone_id");
        $data->execute();
        while($menu=$data->fetch(PDO::FETCH_OBJ))
            {
                if (${"".$menu->client.""}){echo "oui";}
                if ($menu->colone_mod=="simple") 
                    {
                        if ($menu->type =="href")
                            {echo "<li ><a href='".$menu->lien."' target='".$menu->cible."' >".$menu->nom."</a></li>".$menu->option1." ".$menu->option2." ".$menu->option3;}
                        elseif ($menu->type =="onclick")
                            {echo "<li ><a href='#' onclick='".$menu->lien."' target='".$menu->cible."' >".$menu->nom."</a></li>".$menu->option1." ".$menu->option2." ".$menu->option3;}
                        else {echo "<li><a href='".$menu->lien."'>".$menu->colone."</a></li>";}

                    }
                elseif ($menu->colone_mod=="multi")
                    {
                        if ($last!=$menu->colone) 
                            {
                                    ?>
                                    <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown"><?php echo $menu->colone;?> <span id="tot_forum"></span><b class="caret"></b></a>
                                        <ul class="dropdown-menu">
                                        <?php 
                                            $data2 = $DBPDO1->prepare("SELECT * FROM site_menu WHERE colone ='$menu->colone' and colone_mod='dep' ORDER BY position");
                                            $data2->execute();
                                            while($menu2=$data2->fetch(PDO::FETCH_OBJ))
                                                {
                                                    if ($menu2->type =="divider") {echo "<li class='divider'></li>";}
                                                    else{ 
                                                            if ($menu2->type =="href")
                                                                {echo "<li ><a href='".$menu2->lien."' target='".$menu2->cible."' >".$menu2->nom."</a></li>".$menu2->option1." ".$menu2->option2." ".$menu2->option3;}
                                                            elseif ($menu2->type =="onclick")
                                                                {echo "<li ><a href='#' onclick='".$menu2->lien."' target='".$menu2->cible."' >".$menu2->nom."</a></li>".$menu2->option1." ".$menu2->option2." ".$menu2->option3;}
                                                            else {echo "<li><a href='".$menu->lien."'>".$menu->colone."</a></li>";}

                                                        }
                                                }
                                         ?>
                                        </ul>
                                    </li>
                                    <?php
                            }
                        $last=$menu->colone;
                    }
                elseif ($menu->colone_mod=="dep"){}
                else { ?><pre> <?php var_dump($menu); ?></pre><br> <?php }

            }
    }
?>
        </ul>
    </div>
</nav>

voilà

@+

bonjour, je te présente ici un systeme identique que j'ai mis en place pour personaliser ma vresion du tuto MVC de A à Z de grafickart et qui
marche très bien. tu as juste à l'adapter à ton code.

public function getMenu()
    {
        $d = array();
        /* Remplacer ceci par ta requete sql
        $this->loadModel('Menu');
        if(!$d = $this->Menu->fetchAll()) return false;*/
        //la requete me retourne le resultat sous forme d'objet cette fonction va le transformer en tableau
        $toArr=function()use($d)
        {
        if(!is_object($d) and !is_array($d))
        return $d;
        if(is_object($d)) $d = get_object_vars($d);
        return array_map($toArr, $d);
        };
        //ici je le transforme      
        $d = $toArr();
 //cette fonction va pour chaque parent créer un sous tableau 'childs' et y placer tous les elements enfants
        $prepare=function($arr)
        {
          krsort($arr);
          foreach ($arr as $k => &$item):
            if (is_numeric($item'parentid'])):
              $parent = $item'parentid'];
              if (empty($arr$parent]'childs'])) $arr$parent]'childs'] = array();
              array_unshift($arr$parent]'childs'],$item);
              unset($arr$k]);
            endif;
          endforeach;
          ksort($arr);
          return $arr;
        };
        $d=$prepare($d);
        //$this->set($d);
        return $d;
    }

et l'affichage, tu as ceci:

/**
*
*
**/
public function buildMenu($menu, $attributes='')
{
        // Were any attributes submitted? If so generate a string
        if (is_array($attributes)):
            $atts = array();
            foreach ($attributes as $key => $val)
                $atts]= "$key=\"$val\"";
            $attributes = implode(' ',$atts);
        endif;
    $html = (is_string($attributes) and strlen($attributes) > 0) ? '<ul '.$attributes.'>':'<ul>';
    foreach ($menu as $item)
    {
      $html .= '<li><a href="'.Router::url($item->url).'" title="'.$item->name.'" >'.$item->name.'</a>';
      if (isset($item'childs']) and !empty($item'childs'])) $html .= $this->buildMenu($item'childs'],$attributes);
      $html .= '</li>';
    } 
    return $html .= '</ul>';
}

en te relisant je me rend compte que tu as peut être un problème de logique dans la mise en place de ton projet.

Voici ma table :
(le 0 de la colonne "Parent" indique les intitulés de chaque menu, le 1, les sous-menus)

çà se dirai plutot etre comme ceci:

Voici ma table :
(les elements dont la colonne "Parent" vaut 0 representent la racine ("top level") de notre menus,
 tout autre valeur correspond à l'id de son parent)
ID PARENT URL NOM
1 0 '/' accueil
2 0 '/project' portfolio    
3 0 '/help' support        
4 1 '/about' presentation (parent ==> accueil) niveau 1
5 3 '/contact' contact (parent ==> support) niveau 1
6 3 '/faq' foire aux questions (parent ==> support) niveau 1
7 2 '/php' projets php (parent ==> portfolio) niveau 1
8 2 '/java' projets java (parent ==> portfolio) niveau 1
9 7 '/website' sites web (parent ==> projets php) niveau 2
10 7 '/script' scripts (parent ==> projets php) niveau 2

et le code que j'ai posté precedemment fonctionnera sans probleme

Bonjour,

Je vous remercie à tous les deux d'avoir pris le temps de me répondre mais, vraiment, je débute alors vos codes sont quasiment incompréhensibles pour moi. Je pense que je vais laisser tomber et je vais rester sur une présentation du menu "classique", quitte à écrire 100 lignes de code répétitif.

@ flo3376 : Je te remercie mais j'ai besoin d'une solution moins complexe, vu que j'ai une table tout simple. Je suis incapable de "réduire" ton code en enlevant tous les éléments dont je n'ai pas besoin (alignement à gauche, à droite, onclick, etc.)

@iriven : Je te remercie pour ta remarque, effectivement, je pense que mon raisonnement n'étais pas adapté à ce que je voulais faire, du coup j'ai modifié ma table. En revanche, dans la solution que tu proposes tu utilises de la POO avancée, pour moi c'est du Chinois. Typiquement je ne comprends pas à quoi correspond l'élément "$attributes", d'où ça vient, où a-t-il été défini.

Tu parles de MVC : j'ai l'impression qu'il faudrait que je fasse un travail en amont pour définir des classes, des controlleurs et tout le bazar (typiquement à un moment donné tu inclus un "routeur" dans ton code ; je ne pense pas que ça puisse fonctionner dans l'état actuel de mon code). Le système me signale une erreur (syntax error, unexpected T_FUNCTION) pour la fonction $toArr=function()use($d) ...

Encore merci à tous les deux !

dommage de ne pas avoir pu t'aider, ça sera une prochaine fois, bon courage dans ta recherche

@+

Flo

oui. dommage!!
mais pour l'erreur dont ut parles, il s'agit certainement d'une mauvaise utilisation du code que j'ai posté car je confirme qu'il fonctionne sans probleme.