Bonjour,

je suis entrain de faire un site sous cake php, avec un menu dynamique, qui va me permettre d'afficher une liste de lien dans une catégorie.
J'ai donc regardé le tuto de Grafikart sur le Tree Behavior.

Ma question est comment faire pour indiquer au menu de faire le lien vers mes pages, sachant que la gestion de mes pages se fait comme dans le tuto Création d'un site A à Z avec cakephp.

Merci à vous pour votre aide.

3 réponses


la rajoute quelques champs dans la structure de la table 'menus',
j'ai ici mis lien pour le lien du menu, et slug comme son nom l'indique dans le cas ou tu veux gérer les slug (niveau routeur, controller, paginator etc....)

CREATE TABLE IF NOT EXISTS `menus` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `parent_id` int(11) DEFAULT NULL,
  `lft` int(11) DEFAULT NULL,
  `rght` int(11) DEFAULT NULL,
  `lien` varchar(250) DEFAULT NULL,
  `slug` varchar(250) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

a titre d'exemple voila un admin_index

public function admin_index() {
        // if($this->Menu->verify()==false) die('Arbre corrompu');
        $this->set('title_for_layout','Gestion des menus');

        $data = $this->Menu->generateTreeList(null, null, null, ' --- ');
        $this->Menu->recursive = 0;
        $this->paginate = array('order' => array('lft' => 'asc',));
        $this->set('menus', $data);
        $this->set('data', $data);
        $this->set('table', $table);
                // ici je récupère le nombre d'enfant que je vais afficher prés de chaque menu dans ma vue admin_index
        foreach($data as $k=>$v)
            $child$k]=$this->Menu->childCount($k);
        $this->set('childCount',$child);    
    }

dans mon menu (bootstrap)(niveau /elements/menu.ctp) je fait:

<?php
    $out = "<ul class='nav nav-pills'>";

        $depth = 0;
        $prev_depth = 0;
        $count = 0;
        $tagli=$taga=$tagu=$caret="";
        $indice='';
        foreach ($menu as $id => $node) {
            $depth = strrpos($node, '%');       
            if ($depth === false) {
                $depth = 0;
                $clean_node = $node;
            } else {
                $depth = $depth + 1;
                $clean_node = substr($node, strrpos($node, '%')+1);
            }

            if($sousmenu$id]>0){
                $link="#";
                if($depth==0){
                    $tagli=' class="dropdown"';
                    $caret=' <b class="caret"></b>';    
                    }
                else{
                    $tagli=' class="dropdown-submenu"';
                    $caret='<b class="right-caret"></b>';   
                    }
                if($depth==0) 
                    $taga=' data-toggle="dropdown" class="dropdown-toggle"';
                else
                    $taga='';

            }
            else
            {
                $link=$this->webroot.($menuliens$id]'lien']==''?'#':$menuliens$id]'lien']);

                if(strrpos($link,$this->params->url)===false){
                    $tagli='';      
                }
                else {
                    $tagli='class="active"';
                }
                $taga='';
                $caret='';  
            }
            if($link==$this->webroot."[home]"){
            $link=$this->webroot;
            if(!$this->params->url)
                {
                    $tagli='class="active"';
                }
            }

            if ($depth > $prev_depth) {
                $out .= "\n<ul class='dropdown-menu'>\n";
            } else if ($depth < $prev_depth) {
                for ($i = 0; $i < ($prev_depth-$depth); $i++) {
                    $out .= "</li></ul>\n";
                }
            } else if ($count>0) {
                $out .= "\n</li>\n";
            }

            if($clean_node =="-")   
                $out.="<li class='divider'>";
            else            
                $out .= '<li id="node_' . $id . '" '.$tagli.'><a href="'.$link.'" '.$taga.'>'. $clean_node .$caret.'</a>';
            $out .= "\n";
            $prev_depth = $depth;
            $count++;
        }
        for ($i = 0; $i < ($depth); $i++) {
            $out .= "</li></ul>\n";
        }
        if (!empty($tree)) {
            $out .= '</li>';
        }
        $out.='</ul>';

  echo $out;

je m'explique, si quelqu'un au niveau du lien à ecrit [home] cela enverra vers la page d'acceuil (bref tout dépend du routage), et j'ai également introduit la gestion de changement de classe pour le menu actif en me basant sur une comparaison entre le champ "lien" et la valeur de $this->params->url.

Penses également à utiliser les fonctions suivante moveup et movedown (pour monter ou descendre d'un niveau) j'ai aussi fait deux petites fonctions movetop et movebottom qui m'aide beaucoup, quand je créer un sous menu il descend tout en bas! donc pour ne pas me casser la tête et cliquer X fois sur le liens vers l'action moveup ou movedown pour le mettre au debut ou à la fin je pointe vers movetop ou movebottom et déja ca me permet un déplacement plus rapide (en précisant que $delta peut être configuré et faire des déplacement de plusieurs unité

public function admin_moveup($id=null, $delta = 1) {
        if($id==null)
            $this->redirect(array('action'=>'index'));
        $this->Menu->id = $id;
        if(($this->Menu->moveUp($id,abs($delta)))==false) 
            $this->Session->setFlash('Ce Menu ne peut pas monter plus haut','notiferror');
        $this->redirect(array('action'=>'index'));
     }

    public function admin_movedown($id=null, $delta = 1) {
        if($id==null)
            $this->redirect(array('action'=>'index'));
        $this->Menu->id = $id;
        if($this->Menu->moveDown($id,abs($delta))==false)
            $this->Session->setFlash('Ce Menu ne peut pas descendre plus bas','notiferror');
        $this->redirect(array('action'=>'index'));
     }

    public function admin_movetop($id=null, $delta = 1) {
        if($id==null)
            $this->redirect(array('action'=>'index'));
        $this->Menu->id = $id;
        while(($this->Menu->moveUp($id,abs($delta)))){}
        $this->redirect(array('action'=>'index'));
     }

    public function admin_movebottom($id=null, $delta = 1) {
        if($id==null)
            $this->redirect(array('action'=>'index'));
        $this->Menu->id = $id;
        while($this->Menu->moveDown($id,abs($delta))){}

        $this->redirect(array('action'=>'index'));
     }

PS rappel toi que les déplacements ce font au même niveau
si tu as par exemple

A
|---A1
|---A2
|---A3
B
|---B1
|---B2
|---B3

et que tu déplace par exemple B3 ca se fera toujours sous le noeud B
Si c'est pouyr déplacer A2 ca sera sous le noeud A
:)
Voila je sais pas si j'ai répondu, en cas de soucis je suis la :)
bonne continuation

TraxX
Auteur

Alors là un grand merci à toi je vais de ce pas étudier tout ça...

Je reviendrais pour te dire si j'ai eu des soucis ou pas. Mais juste une question quand j'edite un article dans mon formulaire post, je mettais le slug du coup, je dois gérer cette partie comment?

Et encore merci de ton aide.

Avant tout je précise que dans le code que je t'ai mis il n'y a aucune gestion du slug
Dans ton cas disons que ca dépend un peu de ton code...
Mais j'imagine par exemple que pour la gestion des slugs il faudra (très probablement) rajouter de la logique au niveau de la fonction beforeSave() dans ton model Menu.php histoire de vérifier que le slug qui sera rentrée par l'utilisateur est valide (tu peux t'aider en utilisant l' Inflector

// Dans ton fichier app/Model/Menu.php
class User extends AppModel {
 public $actsAs = array('Acl' => array('type' => 'requester'));
// ...
    public function beforeSave($options = array()) {
    parent::beforeSave(); 
    if (isset($this->data'Menu']'slug']) && $this->data'Menu']'slug'] <> '')
         {
             $this->data'Menu']'slug'] = strtolower(Inflector::slug($this->data'Menu']'slug'])); 
         } 
    else  
        {
            unset($this->data'Menu']'slug']);
        } 
    return true;
    }

Note: quand je disais que cela dépend de ton code il faut voir, si par exemple tu a déja une fonction dans ton model Post qui se charge de "slugiser" ton $this->data'Post']'slug'] alors autant y rajouter une partie pour le menu $this->data'Menu']'slug'] et remonter le tout dans l'AppModel pour gérer cette transformation partout ou tu as un slug à enregistrer.

La question a ce poser légitimement c'est pourquoi je n'ai rien dans mon code qui fait allusion a ce slug qui pourtant existe dans ma base:

primo: c'est vraiment facultatif, genre si je veut que mon menu pointe vers une page précise il faut vraiment que le slug soit identique a celui du post ou de la page en question
il y a ici un bout de code trés intéréssant qui permet de mettre en cache la liste de tous les slugs disponible, ensuite dans la fonction admin_add (et admin_edit) de ton MenusController tu peux passer cette liste en options de ton formulaire:

$this->Form->input('slug',array('label'=>'slug:','placeholder'=>'Veuillez rentrer un slug...','type' => 'select''options'=>Cache::read('post_slugs'));

le code a mettre dans le model serait: ( Source)

function cacheSlugs()
    {
        Cache::delete('post_slugs');

        $posts = $this->find('all', array(
            'fields' => array('slug'),
            'recursive' => -1
        ));

        $slugs = Set::extract('/Post/slug', $posts);

        Cache::write('post_slugs', $slugs);

        return $slugs;
    }

    function afterSave()
    {
        $this->cacheSlugs();
    }

    function afterDelete()
    {
        $this->cacheSlugs();
    }
}

Secundo: Dans mon cas j’envoie directement vers le lien $this->webroot."Nom_du_controller/action_index" donc je met de coté le slug (pour le moment mais j'y viendrais)

Bref dans ton cas ce que tu va devoir rajouter c'est le code qui généré le menu pour changer en ligne 73 (du code que j'ai mis dans ma précédente réponse) la valeur de $link en correspondance avec le format des slugs (en conformité avec ton routage)
je pense que c'est ca! :) je sais pas si j'ai pu te répondre comme tu le souhaitais !

Si tu as d'autres questions je suis toujours la :)