PHP / MySQL: Multi-level arbre de catégories

  • Impel GD
  • Professor
  • Professor
  • No Avatar
  • Inscription: Oct 26, 2004
  • Messages: 834
  • Loc: Cologne, Germany
  • Status: Offline

Message Novembre 7th, 2006, 7:49 am

Salut à tous,

J'ai besoin de créer un "arbre" d'une structure multi-classe, avec une case à cocher pour chaque catégorie, basée sur les données d'une table MySQL.

Code: [ Select ]
mysql> SELECT ID, ParentID FROM ProductCategories;
+-----+----------+
| ID | ParentID |
+-----+----------+
|  1 |    0 |
|  2 |    0 |
|  3 |    0 |
|  4 |    0 |
|  5 |    0 |
|  6 |    0 |
|  7 |    0 |
|  8 |    0 |
|  9 |    1 |
| 10 |    1 |
| 11 |    1 |
| 12 |    1 |
| 13 |    1 |
| 14 |    1 |
| 15 |    9 |
| 16 |    9 |
| 17 |    9 |
| 18 |    9 |
| 19 |    9 |
| 20 |    9 |
| 21 |    9 |
| 22 |    9 |
| 23 |    9 |
| 24 |    9 |
| 25 |    2 |
| 26 |    2 |
| 27 |    2 |
  1. mysql> SELECT ID, ParentID FROM ProductCategories;
  2. +-----+----------+
  3. | ID | ParentID |
  4. +-----+----------+
  5. |  1 |    0 |
  6. |  2 |    0 |
  7. |  3 |    0 |
  8. |  4 |    0 |
  9. |  5 |    0 |
  10. |  6 |    0 |
  11. |  7 |    0 |
  12. |  8 |    0 |
  13. |  9 |    1 |
  14. | 10 |    1 |
  15. | 11 |    1 |
  16. | 12 |    1 |
  17. | 13 |    1 |
  18. | 14 |    1 |
  19. | 15 |    9 |
  20. | 16 |    9 |
  21. | 17 |    9 |
  22. | 18 |    9 |
  23. | 19 |    9 |
  24. | 20 |    9 |
  25. | 21 |    9 |
  26. | 22 |    9 |
  27. | 23 |    9 |
  28. | 24 |    9 |
  29. | 25 |    2 |
  30. | 26 |    2 |
  31. | 27 |    2 |


Par exemple, toutes catégories avec un Pare Notiô de «1» apparaît en retrait sous la catégorie dont l'ID est "1".

Je suppose Ill nécessité de créer un tableau multi-dimensionnel, et ensuite à travers la boucle pour créer la liste, mais Im un peu perdu sur la façon de s'y prendre.

Many thanks.
Web and print design
  • Anonymous
  • Bot
  • No Avatar
  • Inscription: 25 Feb 2008
  • Messages: ?
  • Loc: Ozzuland
  • Status: Online

Message Novembre 7th, 2006, 7:49 am

  • Nightslyr
  • Proficient
  • Proficient
  • No Avatar
  • Inscription: Sep 21, 2005
  • Messages: 274
  • Status: Offline

Message Novembre 7th, 2006, 9:34 am

Im à un peu de perte avec ce que vous essayez de faire. Sont les cases à cocher quelque chose que l'utilisateur aura accès (Im devine qu'elle est, comme votre table suggère un magasin)? Quand les cases sont cochées, vous souhaitez que les éléments propres à cette catégorie à afficher, corriger? Si oui, pourquoi ne pas utiliser une combinaison de PHP et JavaScript?

PHP serait quelque chose comme:
Code: [ Select ]
$query = "SELECT * FROM ProductCategories WHERE ParentID=1";
$result = mysql_query($query);

if(mysql_num_rows($result) > 0){
  echo "<div id="parentCat1">
  while($row = mysql_fetch_assoc($result)){
   //build your items
  }
}

$query = "SELECT * FROM ProductCategories WHERE ParentID=2";
.
.
.
  1. $query = "SELECT * FROM ProductCategories WHERE ParentID=1";
  2. $result = mysql_query($query);
  3. if(mysql_num_rows($result) > 0){
  4.   echo "<div id="parentCat1">
  5.   while($row = mysql_fetch_assoc($result)){
  6.    //build your items
  7.   }
  8. }
  9. $query = "SELECT * FROM ProductCategories WHERE ParentID=2";
  10. .
  11. .
  12. .


Avec JavaScript, vous pouvez ensuite utiliser un gestionnaire d'événements pour les cases à cocher:
Code: [ Select ]
//assuming the checkboxes have a name that follows the ParentID (parent1, parent2, etc)

function init(){

var boxes = new Array();

getBoxes();
attachBoxEvents();
}

function getBoxes(){
  var inputs = document.getElementsByTagName('input');
  for(var i = 0; i < inputs.length; i++){
   if(inputs[i].type == "checkbox" && inputs[i].name.search(/parent/) >= 0){
     boxes[boxes.length] = inputs[i];
   }
  }
}

function attachBoxEvents(){
   for(var i = 0; i < boxes.length; i++){
     boxes[i].onclick = showAndHide();
   }
}

function showAndHide(evt){
  evt = (evt) ? evt : ((event) ? event : NULL);
  if(evt){
   var elem = (evt.target) ? evt.target : ((evt.srcElement) ? evt.srcElement : NULL);
   if(elem){
     var index = elem.name.match([0-9]/g);
     var div = document.getElementById('parentCat' + index);
     if(div.style.display == 'block'){
      elem.style.display = '';
     }

     else{
      div.style.display = 'block';
     }
   }
  }
}

window.onload = init;
  1. //assuming the checkboxes have a name that follows the ParentID (parent1, parent2, etc)
  2. function init(){
  3. var boxes = new Array();
  4. getBoxes();
  5. attachBoxEvents();
  6. }
  7. function getBoxes(){
  8.   var inputs = document.getElementsByTagName('input');
  9.   for(var i = 0; i < inputs.length; i++){
  10.    if(inputs[i].type == "checkbox" && inputs[i].name.search(/parent/) >= 0){
  11.      boxes[boxes.length] = inputs[i];
  12.    }
  13.   }
  14. }
  15. function attachBoxEvents(){
  16.    for(var i = 0; i < boxes.length; i++){
  17.      boxes[i].onclick = showAndHide();
  18.    }
  19. }
  20. function showAndHide(evt){
  21.   evt = (evt) ? evt : ((event) ? event : NULL);
  22.   if(evt){
  23.    var elem = (evt.target) ? evt.target : ((evt.srcElement) ? evt.srcElement : NULL);
  24.    if(elem){
  25.      var index = elem.name.match([0-9]/g);
  26.      var div = document.getElementById('parentCat' + index);
  27.      if(div.style.display == 'block'){
  28.       elem.style.display = '';
  29.      }
  30.      else{
  31.       div.style.display = 'block';
  32.      }
  33.    }
  34.   }
  35. }
  36. window.onload = init;
  • Impel GD
  • Professor
  • Professor
  • No Avatar
  • Inscription: Oct 26, 2004
  • Messages: 834
  • Loc: Cologne, Germany
  • Status: Offline

Message Novembre 7th, 2006, 9:58 am

Merci pour la réponse - désolé je n'ai pas fait les choses plus claires.

La page en question fait partie d'un backend admin système. Les cases à cocher que j'ai mentionnés sera là pour les différentes catégories à être affectées à un produit (plus d'une catégorie mai être attribué à un produit) et la liste de chaque catégorie auront une case à cocher visibles en permanence. Toutefois, les mauvais (j'espère) être en mesure de faire face à ces moi-même...

Le problème, c'est la sortie de différentes catégories dans le bon ordre et dans la bonne heirachy. Jaimerais faire d'une manière qui ne sera pas limitée à une certaine profondeur, et naturellement tenir compte de ce qui est dans les ProductCategories table. Im attendons à utiliser imbriquées ULS.

Edit: Ive été à la recherche cet essaie de voir comment je pourrais l'utiliser pour faire le travail, mais mon cerveau qui souffrent de la surchauffe. J'ai une connaissance de base de tableaux et d'enregistrements, mais je suis bloqué sur la façon de les utiliser dans ce cas.
Web and print design
  • Nightslyr
  • Proficient
  • Proficient
  • No Avatar
  • Inscription: Sep 21, 2005
  • Messages: 274
  • Status: Offline

Message Novembre 7th, 2006, 10:59 am

Oui, multi-dimensionnels peuvent être une douleur.

Question: ce que vous faites est tributaire de la hiérarchie, sont-elles correctes? En d'autres termes (pour utiliser les cartes à jouer à titre d'exemple), on ne peut pas avoir une prise sans une reine d'abord, sont-elles correctes? Si thats le cas, une boucle à travers le tableau (s) est facile.

Le problème, c'est de cette profondeur est extensible de façon pas un problème. Si cela était C + +, Id suggère de toute une gamme de listes, avec chaque élément de la liste ayant sa propre gamme de produits avec le bon pour ce niveau de la hiérarchie, mais Im pas sûr que PHP est la fonctionnalité pour créer une telle structure de données.
  • Impel GD
  • Professor
  • Professor
  • No Avatar
  • Inscription: Oct 26, 2004
  • Messages: 834
  • Loc: Cologne, Germany
  • Status: Offline

Message Novembre 7th, 2006, 12:02 pm

Oui, l'ordre de la liste est heirarchy-dépendants autant que je veux pour l'afficher comme suit (basé sur la table publiée dans message original):

Code: [ Select ]
Category 1
  Category 9
    Category 15
    Category 16
    Category 17
    Category ...
    Category 24
  Category 10
    etc...
  1. Category 1
  2.   Category 9
  3.     Category 15
  4.     Category 16
  5.     Category 17
  6.     Category ...
  7.     Category 24
  8.   Category 10
  9.     etc...


Chaque entrée doit être accompagné d'une case à cocher, comme nous le verrons.

En fait, j'ai réussi à faire une chose semblable, afin de créer un menu déroulant en deux niveaux pour le site réel, mais, comme vous dites, il fait quel que soit le nombre de niveaux impliqués est plus délicate.

PHP peut créer des tableaux dans les tableaux, si c'est ce que tu veux dire. Ainsi, un élément dans un tableau peut être un tableau, ou non.
Web and print design
  • gisele
  • Expert
  • Expert
  • Avatar de l’utilisateur
  • Inscription: Nov 11, 2004
  • Messages: 583
  • Loc: Nimes (France)
  • Status: Offline

Message Novembre 8th, 2006, 1:09 am

Salut,

Vous devriez regarder autour d'une façon récursive, il est facile de construire une arborescence, avec une fonction récursive.

Vous devez juste vous assurer que votre table SQL sera optimisé avec des index sur les sous cat.

Jetez un oeil à ceci:
http://www.ozzu.com/sutra339655.html#339655

particualry chien enragé et quand je parle d'une fonction récursive et n'hésitez pas à poser des questions si vous êtes intersed dans ce genre de méthode.

Nous pouvons aller plus loin et je peux vous donner un moyen de faire de vue hiérarchique (arborescence) refleting les relations entre les catégories de votre tableau.
____________________
My web site[/url] oh sh..!
  • Impel GD
  • Professor
  • Professor
  • No Avatar
  • Inscription: Oct 26, 2004
  • Messages: 834
  • Loc: Cologne, Germany
  • Status: Offline

Message Novembre 8th, 2006, 2:19 am

Merci beaucoup pour le lien gisele - Im sur la plupart des Im peur, mais la lire lorsque je reviens.
Web and print design
  • Impel GD
  • Professor
  • Professor
  • No Avatar
  • Inscription: Oct 26, 2004
  • Messages: 834
  • Loc: Cologne, Germany
  • Status: Offline

Message Novembre 8th, 2006, 8:41 am

Bon, maintenant Ive lire et de voir que la catégorie de table (s) est / sont interrogés pour chaque liste de catégories. Existe-t-il une façon de frapper la base de données une fois, de créer un tableau multidimensionnel de ma table, puis récursivement parcourir le tableau pour créer le heirarchecal liste?

Merci.
Web and print design
  • gisele
  • Expert
  • Expert
  • Avatar de l’utilisateur
  • Inscription: Nov 11, 2004
  • Messages: 583
  • Loc: Nimes (France)
  • Status: Offline

Message Novembre 8th, 2006, 10:06 am

Pas besoin en fait, il vous suffit simplement de constituer une liste distincte sur le tableau principal des produits (où les identifiants sont générés et uniques).

Sommething comme:

la constitution de la liste:
[php]
$ q = "SELECT ID, DE productName Produits";
$ r = mysql_query ($ q) or die (mysql_error ()."< br /> <br /> ". $ q);
[/ php]
et pour chaque élément que vous reconstruire la généalogie d'appeler la fonction récursive:
[php]
while ($ d = mysql_fetch_array ($ r))
(
echo "<p class=\"node0\">". $ d [1 ]."</ p >";// affichage noeud 0
single_genealogy ($ d [0], 1); / / récupérer et d'afficher la suite de la filiation avec le noeud 1
)
[/ php]

quelle sera la fonction récursive look like?
vous devez définir ce, quelque part au-dessus de l'avant:
[php]
fonction single_genealogy ($ rubrique, $ level = 0)
(
/ / Le fils du noeud courant = les identifiants qui sont jumelés avec ce pare notid
$ q = "SELECT p.ID, productName DE joindre Produits ProductCategories USING (ID) OU Pare notID =". $ catégorie;
$ r = mysql_query ($ q); / / ou de mourir / mail / echo mysql_error ()
$ niveau + +;
while ($ d = mysql_fetch_row ($ q))
(
echo "<p class=\"node".$level."\">". $ d [1 ]."</ p >";// affichage noeud courant: $ d [1]
/ / appel récursif:
single_genealogy ($ d [0], $ level);
)
)
[/ php]

En fait, ce que j'appelle "node". $ level (noeud 1 noeud 2 node3 etc....) Sont des classes CSS pour <p> (par exemple avec des spécificités tiret, de la taille)
selon le niveau de l'arbre.
Si vous n'aimez CSS et de ses classes, on peut aussi imaginer un simple tiret cumulatifs:
avec un #définir tiret = value;

et puis
[php]
echo "<p style=\"text-indent: ".($level * ident)."\">". $ d [1]. "</ p >";// affichage noeud courant: $ d [1]
[/ php]

Eh bien, c'est tout, je pense que tous se regarder comme ça, pas plus, définir la fonction, puis aa la première requête, que la liste des produits et leur nom, et un foreach, nous avons construit et d'affichage est la filiation.

Est-ce logique? :-)
____________________
My web site[/url] oh sh..!
  • Impel GD
  • Professor
  • Professor
  • No Avatar
  • Inscription: Oct 26, 2004
  • Messages: 834
  • Loc: Cologne, Germany
  • Status: Offline

Message Novembre 8th, 2006, 3:15 pm

Un grand merci gisele - la liste des catégories est maintenant en place!

De toute évidence, cette méthode effectue une requête SELECT, chaque fois que la fonction est appelée récursivement - Je me demandais s'il y avait une autre manière. Mais ce n'est pas vraiment un problème de toute façon - cela fait partie d'un administrateur système et ne sera donc pas utilisé tout le temps.

Heres le code je me suis retrouvé comme par votre excellent guide:

[php] / / Crée la liste de cette catégorie
fonction des catégories (catégorie = 0 $, $ level = 0) (
$ query = "SELECT ID, Pare notID, nom de ProductCategories WHERE = $ Pare notID catégorie";
$ result = mysql_query ($ query) or die (mysql_error ());
$ niveau + +;
while ($ row = mysql_fetch_assoc ($ result)) (
echo "<p class=\"catnode$level\"> <input type = \" checkbox \ "id = \" catégorie ". $ row [" ID "]." \ "name = \" catégorie [ ". $ row [" ID "]."] \ "value = \" 1 \ "> <label for = \" catégorie ". $ row [" ID "]." \ ">". $ row [ "Name"]. "</ label> </ p> \ n";
catégories ($ row [ "ID"], $ level);
)
) [/ php]
Merci encore. :D
Web and print design
  • gisele
  • Expert
  • Expert
  • Avatar de l’utilisateur
  • Inscription: Nov 11, 2004
  • Messages: 583
  • Loc: Nimes (France)
  • Status: Offline

Message Novembre 9th, 2006, 1:24 am

Bien,

Votre recherche est juste si vous voulez:
Tous les enfants (ID + nom), pour un ID et non nom actuel + id tous les enfants une identité.

Si c'est ce que vous voulez son OK.

Je me suis rendu compte que vous utilisez un seul tableau.
Voulez-vous dire que chaque chat a pas un seul pare max?
si oui, pas de problème.

Ou avez-vous de doubler une catégorie qui a plus d'un pare pas (si possible)?
dans ce cas, avec un quelque chose comme ça (enfant n <=> n pare démunis), il serait préférable de diviser à 2 tableaux:
table des catégories et des relations de table, et une requête comme le mien.


Pour la performance:

en fait, vous pouvez optimiser ce genre de choses juste de mettre un index sur Pare notId, qui optimzed la clause where.
Si vous souhaitez ajouter une clause ORDER BY, par exemple, pour trier les enfants par leur nom, alors vous devrez mettre un index sur ce domaine également.

Pour la charge sur le serveur MySQL,
Si vous me dites que vous aurez plus de quelques centaines de milliers d'entrées pour un trafic public, je vais vous dire de vérifier le sérieux de ressources de serveur, sauf si vous faites une nappe de pagination (avec une limite à la première requête (celle avant l'appel à des catégories ())

Mais rien, l'utilisation de cette fonction récursive pour les tâches admin pas de problème, veillez à mettre l'index droit, afin d'optimiser la requête peu importe le nombre de catégories sont dans le tableau.
____________________
My web site[/url] oh sh..!
  • gisele
  • Expert
  • Expert
  • Avatar de l’utilisateur
  • Inscription: Nov 11, 2004
  • Messages: 583
  • Loc: Nimes (France)
  • Status: Offline

Message Novembre 9th, 2006, 1:36 am

Dernière chose très importante.

Un Id musnt être répétées dans une filiation othewise la fonction récursive sera en boucle pour l'éternité.

exemple

cat = 1> 9 = cat> cat17 => cat9 oups! cat17 => cat9 at17 => cat9 at17 => cat9 at17 => cat9 at17 => cat9 at17 => cat9 at17 => cat9 at17 => cat9..........
____________________
My web site[/url] oh sh..!
  • akazdenko
  • Born
  • Born
  • No Avatar
  • Inscription: Jan 14, 2007
  • Messages: 2
  • Loc: Croatia
  • Status: Offline

Message Janvier 14th, 2007, 12:49 pm

salut à tous...

ive trouvé très utile de ce sujet et ive got one question: J'ai une table avec l'identifiant, le nom, id_pare pas et j'ai essayé de créer un arbre imbriqués comme la mise en oeuvre de D.ieu dit:

Thème 1
--- Thème 2
Thème 3 ------
------ Thème 4
Thème 5 ---------
Thème 6
Thème 7
--- Sujet 8
------ Thème 9
Thème 10 ------
--------- Thème 11
------------ Rubrique 12
--------------- 13 Sujet
--------------------- Thème 14
------------------- - Sujet 15
--------- Thème 16
Rubrique 17

etc...

ive essayé d'utiliser votre code, mais sans succès :(

toute aide, s'il vous plaît?

merci d'avance

Zdenko, Croatie
  • knexor2
  • Proficient
  • Proficient
  • Avatar de l’utilisateur
  • Inscription: Mai 27, 2006
  • Messages: 445
  • Loc: US
  • Status: Offline

Message Janvier 14th, 2007, 11:38 pm

J'ai fait quelque chose de similaire à ceci une fois. Fondamentalement, vous avez une seule table avec auto incrémentée identifiants, un nom (pour des exemples bien), et un pare ID pas, lorsque le pare ID réfère pas à un autre poste dans le même tableau, d'un pare pas de 0 se référant à un haut au niveau du point. Tout d'abord, est-il nécessaire que le résultat de la hiérarchie dans une structure de données, ou peut-elle être imprimée directement sur la page?

De toute façon, la chose que j'ai faite a pris tous les éléments et pare démunis et imprimé hiérarchie mode un <select> (étirée à prévenir déroulante action). C'est une solution récursive, BTW...

Le tableau est formaté comme

+-------------------------+
| ID | Nom | Pare pas |

[php]
<? PHP

$ db_host = "localhost";
$ db_un = "username";
$ db_pass = "password";
$ Item_DB = "Base de données contenant le point de table";
$ table = "Le tableau contenant les éléments";

$ link = mysql_connect ($ db_host, db_un $, $ db_pass);

$ tab = ""; / / ceci est de 8 places, qui fonctionne comme un pseudo-caractère de tabulation à l'intérieur de la <option> s
tablvl $ = 1;
fonction print_kids ($ pos) (/ / $ pos est la position actuelle de l'intérieur la hiérarchie (curr articles ID)
global $ link;
global $ tab;
global $ tablvl;
$ pos = ($ pos? $ pos: null);
$ query = "SELECT * FROM table WHERE $ pare pas." ($ pos == null? "IS NULL": "=".$ pos);
/ / == NULL pare pas top niveau question. Pour les 0-pare démunis, remplacer "IS NULL" par "= 0"
$ res = mysql_db_query ($ Item_DB, $ query, $ link);
if (! $ res) print (mysql_error ());
while ($ row = mysql_fetch_array ($ res)) (
has_kids $ =
mysql_fetch_array (mysql_db_query ($ Item_DB, "SELECT * from $ table où pare pas = $ row [0]", $ link))! = Null;
print ( "<option value=\"$row[0]\">");
for ($ i = 0; $ i <$ tablvl; $ i + +) print ($ tab);
print ( "$ row [1] </ option> \ n");
if ($ has_kids) (
$ tablvl + +;
print_kids ($ row [0]); / / appel récursif
tablvl $ -;
)
)
)

numrows $ = 1;
$ res = mysql_db_query ($ Item_DB, "SELECT * FROM $ table", $ link);
while (mysql_fetch_array ($ res)) $ numrows + +;
/ / Oui, Im theres assurer une plus grande efficacité façon de le faire :P

print ( "<select name=\"hierarchy\" size=\"$numrows\"> \ n");
print ( "<option value=\"null\" selected=\"selected\"> racine de tous les éléments </ option> \ n");
print_kids ();
print ( "</ select>");

mysql_close ($ link);

?>
[/ php]

Ceci est (évidemment? ) Une version légèrement modifiée de ce que j'avais, mais il devrait faire la même chose. Hope it helps. :D
"People can school you, but you must educate yourself." ~ John Taylor Gatto
Tech Knack Blog
The purpose of these forums is not to get an answer, but to learn an answer.
  • akazdenko
  • Born
  • Born
  • No Avatar
  • Inscription: Jan 14, 2007
  • Messages: 2
  • Loc: Croatia
  • Status: Offline

Message Janvier 17th, 2007, 10:21 am

avec un léger changement ive got what i need :)

un grand merci aux personnes u forum (merci à knexor2 spéciale et gisele)

cya
  • Anonymous
  • Bot
  • No Avatar
  • Inscription: 25 Feb 2008
  • Messages: ?
  • Loc: Ozzuland
  • Status: Online

Message Janvier 17th, 2007, 10:21 am

Afficher de l'information

  • Total des messages de ce sujet: 18 messages
  • Utilisateurs parcourant ce forum: ScottG et 182 invités
  • Vous ne pouvez pas poster de nouveaux sujets
  • Vous ne pouvez pas répondre aux sujets
  • Vous ne pouvez pas éditer vos messages
  • Vous ne pouvez pas supprimer vos messages
  • Vous ne pouvez pas joindre des fichiers
 
 

© 2011 Unmelted, LLC. Ozzu® est une marque déposée de Unmelted, LLC