Menu déroulant
Fermé
lina_paradis
Messages postés
4
Date d'inscription
jeudi 17 mai 2018
Statut
Membre
Dernière intervention
17 mai 2018
-
Modifié le 17 mai 2018 à 18:00
jordane45 Messages postés 38293 Date d'inscription mercredi 22 octobre 2003 Statut Modérateur Dernière intervention 19 novembre 2024 - 17 mai 2018 à 23:44
jordane45 Messages postés 38293 Date d'inscription mercredi 22 octobre 2003 Statut Modérateur Dernière intervention 19 novembre 2024 - 17 mai 2018 à 23:44
A voir également:
- Menu déroulant
- Menu déroulant excel - Guide
- Excel menu déroulant en cascade - Guide
- Menu déroulant google sheet - Accueil - Guide bureautique
- Windows 11 menu démarrer classique - Guide
- Canon quick menu - Télécharger - Utilitaires
2 réponses
jordane45
Messages postés
38293
Date d'inscription
mercredi 22 octobre 2003
Statut
Modérateur
Dernière intervention
19 novembre 2024
4 704
17 mai 2018 à 18:33
17 mai 2018 à 18:33
Bonjour,
Commence par regarder le code HTML généré ( pour ça tu affiches ta page sur ton navigateur, puis tu fais CTRL+U )
A mon avis, tu dois avec des balises mal fermées.
Bon.. et puis... avoir plusieurs tables pour gérer les différents niveaux de menu....pffff... c'est ( de mon avis..) sacrément brouillon.
Je pense que le mieux est de jouer avec, à minima, une seule table, et de mettre pour chaque item l'id de son parent. (il suffit ensuite de faire du récursif pour obtenir l'arborescence du menu)
Ou mieux... jouer avec la gestion d'arbre intervallaire. (c'est l'idéal pour gérer des listes multi-nivaux). (un peu plus complexe à mettre en œuvre quand on a pas les notions... mais tellement plus simple à manipuler par la suite)...
Commence par regarder le code HTML généré ( pour ça tu affiches ta page sur ton navigateur, puis tu fais CTRL+U )
A mon avis, tu dois avec des balises mal fermées.
Bon.. et puis... avoir plusieurs tables pour gérer les différents niveaux de menu....pffff... c'est ( de mon avis..) sacrément brouillon.
Je pense que le mieux est de jouer avec, à minima, une seule table, et de mettre pour chaque item l'id de son parent. (il suffit ensuite de faire du récursif pour obtenir l'arborescence du menu)
Ou mieux... jouer avec la gestion d'arbre intervallaire. (c'est l'idéal pour gérer des listes multi-nivaux). (un peu plus complexe à mettre en œuvre quand on a pas les notions... mais tellement plus simple à manipuler par la suite)...
jordane45
Messages postés
38293
Date d'inscription
mercredi 22 octobre 2003
Statut
Modérateur
Dernière intervention
19 novembre 2024
4 704
Modifié le 17 mai 2018 à 22:06
Modifié le 17 mai 2018 à 22:06
Je suis actuellement en train de bosser sur le sujet....
Voici de quoi débuter :
Deux fichiers "class"
La class arbre
Et enfin, voici un exemple
Une fois que tu as ce code mis en place et que tes menus s'affichent bien dans une liste UL / LI
Il faut juste ajouter du CSS pour gérer ton menu vertical.
Mais là... ce n'est plus du PHP ....
Tu peux t'inspirer, par exemple, de :
http://www.frogweb.fr/menu-deroulant-vertical/
Voici de quoi débuter :
Deux fichiers "class"
<?php /* * Fichier db.class.php * -> Sert à manipuler la bdd en PDO */ class db { private $bdd = null; private $prepare = NULL; private $res = NULL; private $host = "localhost"; private $user = "root"; private $pwd = "root"; private $port = "3306"; private $dbname ="bdd_arbre"; /** Constructeur */ function __construct($cnxDatas=NULL){ if(!empty($cnxDatas)){ if(is_array($cnxDatas)){ foreach($cnxDatas as $key => $value){ $propName = strtolower($key); if(property_exists('db',$propName)){ $this->{$propName} = $value; } } } } $this->cnx(); } /** * connexion à la BDD */ private function cnx(){ try{ $bdd =new PDO('mysql:host='.$this->host.';dbname='.$this->dbname.'; charset=utf8;port='.$this->port, $this->user, $this->pwd); // Activation des erreurs PDO $bdd->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // mode de fetch par défaut : FETCH_ASSOC / FETCH_OBJ / FETCH_BOTH $bdd->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); } catch(PDOException $e) { die('Erreur : ' . $e->getMessage()); } $this->bdd = $bdd; } /** * Execute une requête SQL */ private function dbQuery($sql,$datas=NULL){ try{ $this->prepare = $this->bdd->prepare($sql) ; $this->res = $this->prepare->execute($datas) ; }catch(Exception $e){ // en cas d'erreur : echo " Erreur ! ".$e->getMessage(); echo " Les datas : " ; print_r($datas); } } public function db_All($sql,$datas=NULL){ $this->dbQuery($sql,$datas); return $this->prepare->fetchAll(); } public function db_One($sql,$datas=NULL){ $this->dbQuery($sql,$datas); return $this->prepare->fetch(); } public function db_Insert($sql,$datas=NULL,$returnId=TRUE){ $this->dbQuery($sql,$datas); return $returnId ? $this->bdd->lastInsertId() : $this->res; } public function db_Exec($sql,$datas=NULL){ $this->dbQuery($sql,$datas); return array('result'=>$this->res,'rowCount'=>$this->prepare->rowCount()); } public function lockTable($tbl){ // lock table to prevent other sessions from modifying the data and thus preserving data integrity $sql = 'LOCK TABLE `' . $tbl . '` WRITE'; $this->db_Exec($sql); } public function unLockTables(){ // lock table to prevent other sessions from modifying the data and thus preserving data integrity $sql = 'UNLOCK TABLES'; $this->db_Exec($sql); } }
La class arbre
<?php /** * Fichier arbre.class.php * Permet de gérer un arbre * * Require db.class.php * ------------------------------- METHODS : ------------------------------- __construct() add() copy() delete() get_descendants() get_descendant_count() get_next_sibling() get_parent() get_path() get_previous_sibling() get_siblings() get_tree() move() to_list() to_select() update() */ class arbre extends db{ private $tbl = 'arbre'; private $col_id = 'id'; private $col_uid = 'uid'; private $col_title = 'title'; private $cg = 'gauche'; private $cd = 'droite'; private $col_parent = 'parent'; private $lookup = array(); function __construct($properties=NULL){ parent::__construct(); $this->setProperties($properties); } private function setProperties($properties=NULL){ if(!empty($properties) && is_array($properties)){ foreach($properties as $key => $value){ $propName = strtolower($key); if( !empty($propName) && property_exists('arbre',$propName) ){ $this->{$propName} = $value; } } } } public function get_FullTree(){ $sql = "SELECT * FROM ". $this->tbl ." ORDER BY ". $this->cg .""; return parent::db_all($sql); } private function _init(){ if(empty($this->lookup)){ $allTree = $this->get_FullTree(); if(!empty($allTree)){ foreach($allTree as $R){ $this->lookup[$R[$this->col_id]] = $R; } } } } /** * Updates the lookup array after inserts and deletes. */ private function _reorder_lookup_array() { $tmp = array(); foreach ($this->lookup as $properties){ ${$this->cg}[] = $properties[$this->cg]; } array_multisort(${$this->cg}, SORT_ASC, $this->lookup); foreach ($this->lookup as $properties){ $tmp[$properties[$this->col_id]] = $properties; } $this->lookup = $tmp; unset($tmp); } public function add($parent, $title, $position = false) { $this->_init(); // make sure parent ID is an integer $parent = (int)$parent; // continue only if if ( // we are adding a topmost node OR $parent == 0 || // parent node exists in the lookup array isset($this->lookup[$parent]) ) { // get parent's descendant nodes (no deeper than the first level) $descendants = $this->get_descendants($parent); // if node is to be inserted in the default position (as the last of the parent node's children) // give a numerical value to the position if ($position === false) $position = count($descendants); // if a custom position was specified else { // make sure that position is an integer value $position = (int)$position; // if position is a bogus number // use the default position (as the last of the parent node's children) if ($position > count($descendants) || $position < 0) $position = count($descendants); } // if parent has no descendants OR the node is to be inserted as the parent node's first child if (empty($descendants) || $position == 0) // set the boundary - nodes having their "left"/"right" values outside this boundary will be affected by // the insert, and will need to be updated // if parent is not found (meaning that we're inserting a topmost node) set the boundary to 0 $boundary = isset($this->lookup[$parent]) ? $this->lookup[$parent][$this->cg] : 0; // if parent node has descendant nodes and/or the node needs to be inserted at a specific position else { // find the child node that currently exists at the position where the new node needs to be inserted to $slice = array_slice($descendants, $position - 1, 1); $descendants = array_shift($slice); // set the boundary - nodes having their "left"/"right" values outside this boundary will be affected by // the insert, and will need to be updated $boundary = $descendants[$this->cd]; } // iterate through all the records in the lookup array foreach ($this->lookup as $id => $properties) { // if the node's "left" value is outside the boundary if ($properties[$this->cg] > $boundary) // increment it with 2 $this->lookup[$id][$this->cg] += 2; // if the node's "right" value is outside the boundary if ($properties[$this->cd] > $boundary) // increment it with 2 $this->lookup[$id][$this->cd] += 2; } // lock table to prevent other sessions from modifying the data and thus preserving data integrity parent::lockTable($this->tbl); // update the nodes in the database having their "left"/"right" values outside the boundary $this->updateBorne($this->cg,2,$boundary); $this->updateBorne($this->cd,2,$boundary); // insert the new node into the database $nodesDatas = array(); $nodesDatas[$this->col_title] = $title; $nodesDatas[$this->cg] = $boundary + 1; $nodesDatas[$this->cd] = $boundary + 2; $nodesDatas[$this->col_parent] = $parent; $nodesDatas[$this->col_uid] = $boundary + 2; $node = $this->insertNode($nodesDatas); $node_id = $node['id']; $node_uid = $node['uid']; // release table lock parent::unlockTables(); // add the node to the lookup array $this->lookup[$node_id] = array( $this->col_id => $node_id, $this->col_uid => $node_uid, $this->col_title => $title, $this->cg => $boundary + 1, $this->cd => $boundary + 2, $this->col_parent => $parent, ); // reorder the lookup array $this->_reorder_lookup_array(); // return the ID of the newly inserted node return array('id'=>$node_id,'uid'=>$node_uid); } return false; } /** * Creates a copy of a node (including its descendant nodes) as the child node of a given node. * @return mixed Returns the ID of the newly created copy, or FALSE on error. */ public function copy($source, $target, $position = false) { $this->_init(); // continue only if if ( // source node exists in the lookup array AND isset($this->lookup[$source]) && // target node exists in the lookup array OR is 0 (indicating a topmost node) (isset($this->lookup[$target]) || $target == 0) ) { // get the source's children nodes (if any) $source_children = $this->get_descendants($source, false); // this array will hold the items we need to copy // by default we add the source item to it $sources = array($this->lookup[$source]); // the copy's parent will be the target node $sources[0][$this->col_parent] = $target; // iterate through source node's children foreach ($source_children as $child) // save them for later use $sources[] = $this->lookup[$child[$this->col_id]]; // the value with which items outside the boundary set below, are to be updated with $source_rl_difference = $this->lookup[$source][$this->cd] - $this->lookup[$source][$this->cg] + 1; // set the boundary - nodes having their "left"/"right" values outside this boundary will be affected by // the insert, and will need to be updated $source_boundary = $this->lookup[$source][$this->cg]; // get target node's children (no deeper than the first level) $target_children = $this->get_descendants($target); // if copy is to be inserted in the default position (as the last of the target node's children) if ($position === false) // give a numerical value to the position $position = count($target_children); // if a custom position was specified else { // make sure given position is an integer value $position = (int)$position; // if position is a bogus number if ($position > count($target_children) || $position < 0) // use the default position (the last of the target node's children) $position = count($target_children); } // we are about to do an insert and some nodes need to be updated first // if target has no children nodes OR the copy is to be inserted as the target node's first child node if (empty($target_children) || $position == 0) // set the boundary - nodes having their "left"/"right" values outside this boundary will be affected by // the insert, and will need to be updated // if parent is not found (meaning that we're inserting a topmost node) set the boundary to 0 $target_boundary = isset($this->lookup[$target]) ? $this->lookup[$target][$this->cg] : 0; // if target has children nodes and/or the copy needs to be inserted at a specific position else { // find the target's child node that currently exists at the position where the new node needs to be inserted to $slice = array_slice($target_children, $position - 1, 1); $target_children = array_shift($slice); // set the boundary - nodes having their "left"/"right" values outside this boundary will be affected by // the insert, and will need to be updated $target_boundary = $target_children[$this->cd]; } // iterate through the nodes in the lookup array foreach ($this->lookup as $id => $properties) { // if the "left" value of node is outside the boundary if ($properties[$this->cg] > $target_boundary) // increment it $this->lookup[$id][$this->cg] += $source_rl_difference; // if the "right" value of node is outside the boundary if ($properties[$this->cd] > $target_boundary) // increment it $this->lookup[$id][$this->cd] += $source_rl_difference; } // lock table to prevent other sessions from modifying the data and thus preserving data integrity parent::lockTable($this->tbl); // update the nodes in the database having their "left"/"right" values outside the boundary $this->updateBorne($this->cg ,$source_rl_difference,$target_boundary); $this->updateBorne($this->cd ,$source_rl_difference,$target_boundary); // finally, the nodes that are to be inserted need to have their "left" and "right" values updated $shift = $target_boundary - $source_boundary + 1; // iterate through the nodes that are to be inserted foreach ($sources as $id => &$properties) { // update "left" value $properties[$this->cg] += $shift; // update "right" value $properties[$this->cd] += $shift; $node = $this->insertNode($properties); $node_id = $node['id']; // because the node may have children nodes and its ID just changed // we need to find its children and update the reference to the parent ID foreach ($sources as $key => $value){ if ($value[$this->col_parent] == $properties[$this->col_id]){ $sources[$key][$this->col_parent] = $node_id; } } // update the node's properties with the ID $properties[$this->col_id] = $node_id; // update the array of inserted items $sources[$id] = $properties; } // a reference of a $properties and the last array element remain even after the foreach loop // we have to destroy it unset($properties); // release table lock parent::unlockTables(); // at this point, we have the nodes in the database but we need to also update the lookup array $parents = array(); // iterate through the inserted nodes foreach ($sources as $id => $properties) { // if the node has any parents if (count($parents) > 0) // iterate through the array of parent nodes while ($parents[count($parents) - 1]['right'] < $properties[$this->cd]) // and remove those which are not parents of the current node array_pop($parents); // if there are any parents left if (count($parents) > 0) // the last node in the $parents array is the current node's parent $properties[$this->col_parent] = $parents[count($parents) - 1]['id']; // update the lookup array $this->lookup[$properties[$this->col_id]] = $properties; // add current node to the stack $parents[] = array( 'id' => $properties[$this->col_id], 'right' => $properties[$this->cd] ); } // reorder the lookup array $this->_reorder_lookup_array(); // return the ID of the copy return $sources[0][$this->col_id]; } // if scripts gets this far, return false as something must've went wrong return false; } private function updateBorne($borne = 'cd',$source_rl_difference,$target_boundary,$aom='+',$compare='>'){ $sql = 'UPDATE `' . $this->tbl . '` SET `' . $borne . '` = `' . $borne . '` '.$aom.' ' . $source_rl_difference . ' WHERE `' . $borne . '` '.$compare.' ' . $target_boundary . ';'; parent::db_Exec($sql); } private function insertNode($properties=array()){ $sql = 'INSERT INTO `' . $this->tbl . '`(`' . $this->col_uid . '`,`' . $this->col_title . '`,`' . $this->cg . '`, `' . $this->cd . '`, `' . $this->col_parent . '`) VALUES (:uid,:title,:cg,:cd,:parent)'; $uid = uniqid('ai',false); $datas = array(':uid'=>$uid, ':title'=> $properties[$this->col_title], ':cg'=> $properties[$this->cg], ':cd'=> $properties[$this->cd], ':parent'=> $properties[$this->col_parent] ); return array('id'=>parent::db_Insert($sql,$datas, TRUE),'uid'=>$uid); } /** * Deletes a node, including the node's descendant nodes. */ public function delete($node = 0) { $this->_init(); if (isset($this->lookup[$node])) { // get target node's descendant nodes (if any) $descendants = $this->get_descendants($node, false); // iterate through target node's descendant nodes foreach ($descendants as $descendant){ // remove node from the lookup array unset($this->lookup[$descendant[$this->col_id]]); } //lock table parent::lockTable($this->tbl); //Delete nodes from the database $sql = "DELETE FROM " . $this->tbl ." WHERE ". $this->cg . ' >= ' . $this->lookup[$node][$this->cg] . " AND ". $this->cd . " <= " . $this->lookup[$node][$this->cd] ; parent::db_Exec($sql); // the value with which items outside the boundary set below, are to be updated with $target_rl_difference = $this->lookup[$node][$this->cd] - $this->lookup[$node][$this->cg] + 1; // set the boundary - nodes having their "left"/"right" values outside this boundary will be affected by // the insert, and will need to be updated $boundary = $this->lookup[$node][$this->cg]; // remove the target node from the lookup array unset($this->lookup[$node]); // iterate through nodes in the lookup array foreach ($this->lookup as $id => $properties) { // if the "left" value of node is outside the boundary if ($this->lookup[$id][$this->cg] > $boundary){ // decrement it $this->lookup[$id][$this->cg] -= $target_rl_difference; } // if the "right" value of node is outside the boundary if ($this->lookup[$id][$this->cd] > $boundary){ // decrement it $this->lookup[$id][$this->cd] -= $target_rl_difference; } } // update the nodes in the database having their "left"/"right" values outside the boundary $this->updateBorne($this->cg,$target_rl_difference,$boundary,'-'); $this->updateBorne($this->cd,$target_rl_difference,$boundary,'-'); // release table lock parent::unLockTables(); // return true as everything went well return true; } return false; } /** * Returns an unidimensional (flat) array with the descendant nodes of a given parent node. */ public function get_descendants($node = 0, $direct_descendants_only = true) { $this->_init(); if (isset($this->lookup[$node]) || $node === 0) { $descendants = array(); $keys = array_keys($this->lookup); foreach ($keys as $item){ if ( $this->lookup[$item][$this->cg] > ($node !== 0 ? $this->lookup[$node][$this->cg] : 0) && $this->lookup[$item][$this->cg] < ($node !== 0 ? $this->lookup[$node][$this->cd] : PHP_INT_MAX) && (!$direct_descendants_only || $this->lookup[$item][$this->col_parent] == $node) ){ $descendants[$this->lookup[$item][$this->col_id]] = $this->lookup[$item]; } } return $descendants; } return false; } /** * Returns the number of descendant nodes of a given node. */ public function get_descendant_count($node=0, $direct_descendants_only = true) { $this->_init(); if (isset($this->lookup[$node])){ if (!$direct_descendants_only){ return ($this->lookup[$node][$this->cd] - $this->lookup[$node][$this->cg] - 1) / 2; }else { $result = 0; foreach ($this->lookup as $id => $properties){ if ($this->lookup[$id][$this->col_parent] == $node){ $result++; } } return $result; } } // if script gets this far, return false as something must've went wrong return false; } /** * Returns the next sibling of a node. */ public function get_next_sibling($node = 0) { if ($siblings = $this->get_siblings($node, true)) { $node_position = array_search($node, array_keys($siblings)); $sibling = array_slice($siblings, $node_position + 1, 1); return !empty($sibling) ? array_pop($sibling) : 0; } return false; } /** * Returns an array containing a node's direct parent node if the node has a parent node, or "0" if the node is a * topmost node. */ public function get_parent($node = 0) { $this->_init(); if (isset($this->lookup[$node])){ return isset($this->lookup[$this->lookup[$node][$this->col_parent]]) ? $this->lookup[$this->lookup[$node][$this->col_parent]] : 0; } return false; } /** * Returns an unidimensional (flat) array with the path to the given node (including the node itself). */ public function get_path($node = 0) { $this->_init(); $parents = array(); // if node exists in the lookup array if (isset($this->lookup[$node])){ foreach ($this->lookup as $id => $properties){ if ($properties[$this->cg] < $this->lookup[$node][$this->cg] && $properties[$this->cd] > $this->lookup[$node][$this->cd] ) { $parents[$properties[$this->col_id]] = $properties; } } // add also the node given as argument $parents[$node] = $this->lookup[$node]; } // return the path to the node return $parents; } /** * Returns the previous sibling of a node. */ public function get_previous_sibling($node = 0) { if ($siblings = $this->get_siblings($node, true)) { $node_position = array_search($node, array_keys($siblings)); $sibling = $node_position > 0 ? array_slice($siblings, $node_position - 1, 1) : array(); return !empty($sibling) ? array_pop($sibling) : 0; } return false; } /** * Returns an array with a node's sibling nodes */ public function get_siblings($node, $include_self = false) { if (isset($this->lookup[$node])) { $properties = $this->lookup[$node]; $siblings = $this->get_descendants($properties['parent']); if (!$include_self) unset($siblings[$node]); return $siblings; } return false; } /** * Returns a multidimensional array with all the descendant nodes (including children nodes of children nodes of * children nodes and so on) of a given node. * @return array */ public function get_tree($node = 0) { $descendants = $this->get_descendants($node); foreach ($descendants as $id => $properties){ $descendants[$id]['children'] = $this->get_tree($id); } return $descendants; } /** * move node with descendants */ public function move($source, $target, $position = false) { $this->_init(); // continue only if if ( // source node exists in the lookup array AND isset($this->lookup[$source]) && // target node exists in the lookup array OR is 0 (indicating a topmost node) (isset($this->lookup[$target]) || $target == 0) && // target node is not a child node of the source node (that would cause infinite loop) !in_array($target, array_keys($this->get_descendants($source, false))) ) { // if we have to move the node after/before another node if ($position === 'after' || $position === 'before') { // get the target's parent node $target_parent = $target == 0 ? 0 : $this->lookup[$target]['parent']; // get the target's parent's descendant nodes $descendants = $this->get_descendants($target_parent); // get the target's position among the descendants $keys = array_keys($descendants); $target_position = array_search($target, $keys); // move the source node to the desired position if ($position == 'after') return $this->move($source, $target_parent, $target_position + 1); else return $this->move($source, $target_parent, $target_position == 0 ? 0 : $target_position - 1); } // the source's parent node's ID becomes the target node's ID $this->lookup[$source][$this->col_parent] = $target; // get source node's descendant nodes (if any) $source_descendants = $this->get_descendants($source, false); // this array will hold the nodes we need to move // by default we add the source node to it $sources = array($this->lookup[$source]); // iterate through source node's descendants foreach ($source_descendants as $descendant) { // save them for later use $sources[] = $this->lookup[$descendant[$this->col_id]]; // for now, remove them from the lookup array unset($this->lookup[$descendant[$this->col_id]]); } // the value with which nodes outside the boundary set below, are to be updated with $source_rl_difference = $this->lookup[$source][$this->cd] - $this->lookup[$source][$this->cg] + 1; // set the boundary - nodes having their "left"/"right" values outside this boundary will be affected by // the insert, and will need to be updated $source_boundary = $this->lookup[$source][$this->cg]; // lock table to prevent other sessions from modifying the data and thus preserving data integrity parent::lockTable($this->tbl); // we'll multiply the "left" and "right" values of the nodes we're about to move with "-1", in order to // prevent the values being changed further in the script $sql = 'UPDATE `' . $this->tbl . '` SET `' . $this->cg . '` = `' . $this->cg . '` * -1, `' . $this->cd . '` = `' . $this->cd . '` * -1 WHERE `' . $this->cg . '` >= ' . $this->lookup[$source][$this->cg] . ' AND `' . $this->cd . '` <= ' . $this->lookup[$source][$this->cd] . ''; parent::db_Exec($sql); // remove the source node from the list unset($this->lookup[$source]); // iterate through the remaining nodes in the lookup array foreach ($this->lookup as $id=>$properties) { // if the "left" value of node is outside the boundary if ($this->lookup[$id][$this->cg] > $source_boundary) // decrement it $this->lookup[$id][$this->cg] -= $source_rl_difference; // if the "right" value of item is outside the boundary if ($this->lookup[$id][$this->cd] > $source_boundary) // decrement it $this->lookup[$id][$this->cd] -= $source_rl_difference; } // update the nodes in the database having their "left"/"right" values outside the boundary $this->updateBorne($this->cg,$source_rl_difference,$source_boundary,'-'); $this->updateBorne($this->cd,$source_rl_difference,$source_boundary,'-'); // get descendant nodes of target node (first level only) $target_descendants = $this->get_descendants((int)$target); // if node is to be inserted in the default position (as the last of target node's children nodes) // give a numerical value to the position if ($position === false) $position = count($target_descendants); // if a custom position was specified else { // make sure given position is an integer value $position = (int)$position; // if position is a bogus number if ($position > count($target_descendants) || $position < 0) // use the default position (as the last of the target node's children) $position = count($target_descendants); } // because of the insert, some nodes need to have their "left" and/or "right" values adjusted // if target node has no descendant nodes OR the node is to be inserted as the target node's first child node if (empty($target_descendants) || $position == 0) // set the boundary - nodes having their "left"/"right" values outside this boundary will be affected by // the insert, and will need to be updated // if parent is not found (meaning that we're inserting a topmost node) set the boundary to 0 $target_boundary = isset($this->lookup[$target]) ? $this->lookup[$target][$this->cg] : 0; // if target has any descendant nodes and/or the node needs to be inserted at a specific position else { // find the target's child node that currently exists at the position where the new node needs to be inserted to $slice = array_slice($target_descendants, $position - 1, 1); $target_descendants = array_shift($slice); // set the boundary - nodes having their "left"/"right" values outside this boundary will be affected by // the insert, and will need to be updated $target_boundary = $target_descendants[$this->cd]; } // iterate through the records in the lookup array foreach ($this->lookup as $id => $properties) { // if the "left" value of node is outside the boundary if ($properties[$this->cg] > $target_boundary) // increment it $this->lookup[$id][$this->cg] += $source_rl_difference; // if the "left" value of node is outside the boundary if ($properties[$this->cd] > $target_boundary) // increment it $this->lookup[$id][$this->cd] += $source_rl_difference; } // update the nodes in the database having their "left"/"right" values outside the boundary $this->updateBorne($this->cg,$source_rl_difference,$target_boundary,'+'); $this->updateBorne($this->cd,$source_rl_difference,$target_boundary,'+'); // finally, the nodes that are to be inserted need to have their "left" and "right" values updated $shift = $target_boundary - $source_boundary + 1; // iterate through the nodes to be inserted foreach ($sources as $properties) { // update "left" value $properties[$this->cg] += $shift; // update "right" value $properties[$this->cd] += $shift; // add the item to our lookup array $this->lookup[$properties[$this->col_id]] = $properties; } // also update the entries in the database // (notice that we're subtracting rather than adding and that finally we multiply by -1 so that the values // turn positive again) $sql = 'UPDATE `' . $this->tbl . '` SET `' . $this->cg . '` = (`' . $this->cg . '` - ' . $shift . ') * -1, `' . $this->cd . '` = (`' . $this->cd . '` - ' . $shift . ') * -1 WHERE `' . $this->cg . '` < 0'; parent::db_Exec($sql); //Update the parent of the source node $sql = 'UPDATE `' . $this->tbl . '` SET `' . $this->col_parent . '` = ' . $target . ' WHERE `' . $this->col_id . '` = ' . $source . ''; parent::db_Exec($sql); // release table lock parent::unlockTables(); // reorder the lookup array $this->_reorder_lookup_array(); // return true as everything went well return true; } // if scripts gets this far, return false as something must've went wrong return false; } /** * create html ul/li list * @return (string) liste UL/LI */ public function to_list($node, $list_type='ul', $attributes = '') { if (!is_array($node)) $node = $this->get_tree($node); if (!empty($node)) { // start generating the output $out = '<' . $list_type . ($attributes != '' ? ' ' . $attributes : '') . '>'; // iterate through each node foreach ($node as $elem){ // generate output and if the node has children nodes, call this method recursively $out .= '<li class="arbre_item arbre_item_' . $elem[$this->col_id] . '" >' . '<a data-uid="'.$elem[$this->col_uid].'" class="node-item">'.$elem[$this->col_title] .'</a>' . (is_array($elem['children']) ? $this->to_list($elem['children'], $list_type) : '') . '</li>'; } // return generated output return $out . '</'.$list_type.'>'; } } /** * Mise à jour Node Title */ public function update($node=0, $title='') { $this->_init(); // continue only if target node exists in the lookup array if (isset($this->lookup[$node])) { parent::lockTable($this->tbl); $sql = "UPDATE ". $this->tbl . " SET " . $this->col_title . " = :title WHERE ". $this->col_id . " = :node "; $datas = array(':title'=>$title, ':node'=>$node); parent::db_Exec($sql,$datas); parent::unLockTables(); $this->lookup[$node][$this->col_title] = $title; return true; } return false; } //- FIN DE LA CLASS - // }
Et enfin, voici un exemple
<?php require_once 'db.class.php'; require_once 'arbre.class.php'; //on instancie la class Arbre $mptt = new arbre(); // récupération de l'arbre sous forme de ul li $tree_list = $mptt->to_list(0); ?> <!Doctype html> <html> <head> <title>Arbre</title> <meta charset="utf-8"> </head> <body> <div id='jstree_div'> <?php // Affiche sous forme de liste UL / LI echo $tree_list; ?> </div> </body> </html>
Une fois que tu as ce code mis en place et que tes menus s'affichent bien dans une liste UL / LI
Il faut juste ajouter du CSS pour gérer ton menu vertical.
Mais là... ce n'est plus du PHP ....
Tu peux t'inspirer, par exemple, de :
http://www.frogweb.fr/menu-deroulant-vertical/
lina_paradis
Messages postés
4
Date d'inscription
jeudi 17 mai 2018
Statut
Membre
Dernière intervention
17 mai 2018
17 mai 2018 à 22:56
17 mai 2018 à 22:56
un GRAND MERCI t'es adorable.
lina_paradis
Messages postés
4
Date d'inscription
jeudi 17 mai 2018
Statut
Membre
Dernière intervention
17 mai 2018
17 mai 2018 à 23:02
17 mai 2018 à 23:02
reste que la BD bdd_arbre je te laisse tranquille :(
jordane45
Messages postés
38293
Date d'inscription
mercredi 22 octobre 2003
Statut
Modérateur
Dernière intervention
19 novembre 2024
4 704
17 mai 2018 à 23:44
17 mai 2018 à 23:44
arf. oui ça serait mieux en effet
et un jeu d'exemple
Tu peux, si tu le souhaites, ajouter des champs supplémentaires.
Mais en réalité, il est préférable d'ajouter une table à côté qui serait en relation avec le champ uid ( uid = id unique)
Et un peu de documentation sur la gestion d'arbre intervallaire
https://sqlpro.developpez.com/cours/arborescence/
https://stephanelegrand.wordpress.com/2009/01/03/gestion-dune-structure-darbre-sous-mysql/
L'avantage de représenter ses arborescences de cette façon est de ne pas avoir à gérer de récursif pour parcourir l'arbre.
On peut, en une seule requête, récupérer le contenu de l'arbre entier ou d'une seule branche si l'on le souhaite.
Le code que je t'ai donné est plus complet que ce dont tu as besoin. il permet, en plus de créer l'arbre, de pouvoir modifier / supprimer / déplacer un noeud.
CREATE TABLE IF NOT EXISTS `arbre` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `uid` varchar(20) NOT NULL DEFAULT '0' COMMENT 'id unique', `title` varchar(256) DEFAULT NULL, `gauche` bigint(20) DEFAULT NULL, `droite` bigint(20) DEFAULT NULL, `parent` bigint(20) DEFAULT NULL, PRIMARY KEY (`id`), KEY `cg` (`gauche`), KEY `cd` (`droite`), KEY `parent_id` (`parent`), KEY `uid` (`uid`) ) ENGINE=MyISAM AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
et un jeu d'exemple
DELETE FROM `arbre`; INSERT INTO `arbre` (`id`, `uid`, `title`, `gauche`, `droite`, `parent`) VALUES (1, 'ai5af566457e486', 'Main', 1, 12, 0), (2, 'ai5af5664584775', 'Child 1', 2, 3, 1), (3, 'ai5af56645901b4', 'Child 2', 4, 11, 1), (4, 'ai5af5664596d75', 'Child 2.1', 5, 8, 3), (5, 'ai5af566459cf36', 'Child 2.2', 9, 10, 3), (6, 'ai5af56645a6441', 'Child 3.1', 6, 7, 4);
Tu peux, si tu le souhaites, ajouter des champs supplémentaires.
Mais en réalité, il est préférable d'ajouter une table à côté qui serait en relation avec le champ uid ( uid = id unique)
Et un peu de documentation sur la gestion d'arbre intervallaire
https://sqlpro.developpez.com/cours/arborescence/
https://stephanelegrand.wordpress.com/2009/01/03/gestion-dune-structure-darbre-sous-mysql/
L'avantage de représenter ses arborescences de cette façon est de ne pas avoir à gérer de récursif pour parcourir l'arbre.
On peut, en une seule requête, récupérer le contenu de l'arbre entier ou d'une seule branche si l'on le souhaite.
Le code que je t'ai donné est plus complet que ce dont tu as besoin. il permet, en plus de créer l'arbre, de pouvoir modifier / supprimer / déplacer un noeud.
17 mai 2018 à 21:51