création d'algorithme

Invité
Invité n'ayant pas de compte PHPfrance

21 août 2008, 16:15

Bonjour à tous,
je voudrais créer un système de menu/sous-menus à partir d'une table sql que voici:

Code : Tout sélectionner

CREATE TABLE `jos_vm_category_xref` ( `category_parent_id` int(11) NOT NULL default '0', `category_child_id` int(11) NOT NULL default '0', `category_list` int(11) default NULL, KEY `category_xref_category_parent_id` (`category_parent_id`), KEY `category_xref_category_child_id` (`category_child_id`), KEY `idx_category_xref_category_list` (`category_list`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='Category child-parent relation list'; -- -- Contenu de la table `jos_vm_category_xref` -- INSERT INTO `jos_vm_category_xref` (`category_parent_id`, `category_child_id`, `category_list`) VALUES (0, 1, NULL), (0, 2, NULL), (0, 3, NULL), (0, 4, NULL), (0, 5, NULL), (0, 6, NULL), (5, 55, NULL), (27, 60, NULL), (1, 12, NULL), (1, 13, NULL), (31, 78, NULL), (1, 16, NULL), (1, 17, NULL), (1, 18, NULL), (1, 19, NULL), (2, 21, NULL), (2, 22, NULL), (2, 23, NULL), (2, 24, NULL), (3, 26, NULL), (3, 27, NULL), (3, 28, NULL), (27, 29, NULL), (4, 31, NULL), (4, 32, NULL), (4, 33, NULL), (31, 77, NULL), (4, 76, NULL), (38, 86, NULL), (5, 38, NULL), (5, 39, NULL), (5, 40, NULL), (6, 41, NULL), (2, 56, NULL), (6, 43, NULL), (6, 44, NULL), (28, 61, NULL), (33, 83, NULL), (1, 50, NULL), (0, 51, NULL), (51, 52, NULL), (52, 53, NULL), (2, 57, NULL), (2, 58, NULL), (31, 79, NULL), (32, 81, NULL), (32, 80, NULL), (31, 68, NULL), (38, 69, NULL), (5, 70, NULL), (40, 71, NULL), (39, 72, NULL), (33, 82, NULL), (2, 75, NULL), (76, 84, NULL), (76, 85, NULL), (70, 87, NULL), (55, 88, NULL), (52, 89, NULL), (28, 90, NULL), (5, 172, NULL), (28, 92, NULL), (28, 93, NULL), (0, 109, NULL), (28, 103, NULL), (0, 104, NULL), (104, 105, NULL), (104, 106, NULL), (156, 157, NULL), (26, 158, NULL), (109, 110, NULL), (109, 111, NULL), (109, 112, NULL), (110, 113, NULL), (110, 114, NULL), (111, 115, NULL), (111, 116, NULL), (112, 117, NULL), (112, 118, NULL), (110, 119, NULL), (32, 120, NULL), (27, 135, NULL), (27, 136, NULL), (3, 137, NULL), (75, 131, NULL), (75, 132, NULL), (172, 173, NULL), (3, 134, NULL), (109, 138, NULL), (138, 139, NULL), (111, 140, NULL), (109, 141, NULL), (141, 142, NULL), (1, 143, NULL), (143, 144, NULL), (143, 145, NULL), (1, 146, NULL), (146, 147, NULL), (109, 148, NULL), (148, 149, NULL), (109, 150, NULL), (150, 151, NULL), (109, 152, NULL), (152, 153, NULL), (109, 0, NULL), (109, 156, NULL), (109, 0, NULL), (109, 0, NULL), (150, 155, NULL), (26, 159, NULL), (88, 160, NULL), (71, 161, NULL), (69, 162, NULL), (88, 163, NULL), (71, 164, NULL), (69, 165, NULL), (109, 166, NULL), (166, 167, NULL), (166, 168, NULL), (57, 188, NULL), (82, 170, NULL), (82, 171, NULL), (40, 174, NULL), (38, 175, NULL), (38, 176, NULL), (40, 177, NULL), (172, 178, NULL), (1, 179, NULL), (77, 196, NULL), (1, 181, NULL), (57, 182, NULL), (57, 183, NULL), (2, 184, NULL), (1, 195, NULL), (196, 197, NULL), (77, 198, NULL), (68, 194, NULL), (198, 199, NULL), (77, 200, NULL), (200, 201, NULL), (77, 202, NULL), (202, 203, NULL), (77, 204, NULL), (204, 205, NULL), (204, 206, NULL), (77, 207, NULL), (207, 208, NULL), (77, 209, NULL), (209, 210, NULL), (207, 211, NULL), (77, 212, NULL), (212, 213, NULL), (209, 215, NULL), (212, 216, NULL), (77, 217, NULL), (217, 218, NULL), (217, 219, NULL);
Existe t-il un code ou un principe pour créer une arborescence à partir d'une table organisée ainsi?
Merci pour vos réponses.

ViPHP
ViPHP | 5924 Messages

21 août 2008, 17:36

Tu es conscient que pour reconstruire une petite partie du menu tu vas être obligé de sélectionner tous les enregistrements ?

Invité
Invité n'ayant pas de compte PHPfrance

31 août 2008, 16:55

Oui, j'en suis conscient. Je recherche plus un raisonnement en pseudo code qui me mettrait sur la bonne voie, plutot que le code tout fait.

La table dans le post precedent permet de "mapper" les differentes categories. Je rajoute ci dessous la table principale qui fournit les id de chaque element:

Code : Tout sélectionner

CREATE TABLE `jos_vm_category` ( `category_id` int(11) NOT NULL auto_increment, `vendor_id` int(11) NOT NULL default '0', `category_name` varchar(128) NOT NULL default '', `category_description` text, `category_thumb_image` varchar(255) default NULL, `category_full_image` varchar(255) default NULL, `category_publish` char(1) default NULL, `cdate` int(11) default NULL, `mdate` int(11) default NULL, `category_browsepage` varchar(255) NOT NULL default 'browse_1', `products_per_row` tinyint(2) NOT NULL default '1', `category_flypage` varchar(255) default NULL, `list_order` int(11) default NULL, PRIMARY KEY (`category_id`), KEY `idx_category_vendor_id` (`vendor_id`), KEY `idx_category_name` (`category_name`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT
Le seul champ utile pour le raisonnement est en fait category_id.
Je cherche a faire quelquechose de tres optimise.

La premiere table jos_vm_category_xref a 2 champs utiles pour construire le raisonnement: category_parent_id et category_child_id.

Mon pb est justement la table de mapping jos_vm_category_xref. Chaque element de menu peut avoir un parent et un enfant.

Comme tu dis, il faut certainement selectionner tous les enregistrements de jos_vm_category avec sql, et ensuite faire un foreach php pour analyser la position de chaque enregistrement dans la table de mapping avec des conditions.

La, je bloque un peu car il faut traiter a la fois le cas ou l'element courant a un parent, et le cas ou l'element courant a des enfants.

Merci pour toute aide qui pourrait me mettre sur la voie.

ViPHP
ViPHP | 5924 Messages

31 août 2008, 17:25

Tu n'as pas besoin d'une deuxième table. Il te suffit juste de mettre pour chaque élément l'id du parent dans ta table de catégories.

Après, pour la reconstitution, une implémentation simple serait de placer tous les enregistrements dans un tableau, en associant l'enregistrement à son id, (la catégorie représentée de préférence sous forme d'objet, c'est plus pratique à manipuler, mais après c'est toi qui vois).
Ensuite de parcourir ce tableau, si l'id du parent est 0 ou NULL (enfin c'est toi qui décides quelle id associer à la racine), tu insères l'enregistrement dans un tableau des éléments situés à la racine sinon, dans le tableau des catégories, tu recherches l'id (ca va pas être trop dûr si tu as pris soin d'utiliser l'id pour index), et tu ajoutes l'enregistrement courant aux enfants de l'enregistrement parent.

Attention, une petite subtilité. Comme je te disais, il est préférable de travailler sur des objets. Si tu utilises des tableaux, lorsque tu ajouteras un élément dans le tableau racine ou bien dans les enfants d'un autre élément, il faut absolument faire l'assignation par référence et non par copie…

Invité
Invité n'ayant pas de compte PHPfrance

01 sept. 2008, 10:04

merci pour les conseils. ça pourrait effectivement se faire sans une deuxième table mais je n'ai pas trop le choix car je travaille sur virtuemart, un plugin joomla pour ecommerce.

J'essaye de créeer un menu perso à partir d'une structure existante que je ne peux modifier:
- 1 table qui liste toutes les catégories et leurs id
- 1 table qui "mappe" les relations parent-enfants

Invité
Invité n'ayant pas de compte PHPfrance

01 sept. 2008, 11:07

j'ai réussi à créer une liste pour afficher les éléments de 1er niveau et leurs enfants dans une liste:
$sql1 ="SELECT a.category_name, a.category_id FROM jos_vm_category as a, jos_vm_category_xref as b WHERE a.category_id = b.category_child_id AND b.category_parent_id = 0 ";
$x1 = mysql_query($sql1);
	?>
<div>
    <ul>  
        <?php 		
        while ($niv1 = mysql_fetch_array($x1))
        {
        ?>  
            <li><a href="#"><?php echo $niv1["category_name"]; ?></a></li>
		<?php
			foreach ($niv1 as $elt)
			{
				echo "<ul>";
				$sql2 ="SELECT c.category_name FROM jos_vm_category as c, jos_vm_category_xref as cx WHERE cx.category_parent_id ='". $niv1['category_id'] . "' AND cx.category_child_id = c.category_id";
				$x2 = mysql_query($sql2);
				while ($niv2 = mysql_fetch_array($x2))
				{
				?>
                    <li><a href="#"><?php echo $niv2["category_name"]; ?></a></li>                
                <?php
				}
				echo "</ul>";				
			}
		}
		?>
	</ul>
</div>
2 problèmes:
1 => ça ne marche que pour le premier niveau (parent = 0) + enfants de 2ème niveau, alors que j'ai 3 ou 4 niveux de profondeur
2 => chaque enfant apparait plusieurs fois au lieu d'une seule fois

le résultat visuel:
<div>
    <ul>  
          
            <li><a href="#">Montagne</a></li>
		<ul>                    <li><a href="#">Chaussures</a></li>                
                                    <li><a href="#">Sac à dos</a></li>                
                                    <li><a href="#">Accessoires</a></li>                
                                    <li><a href="#">Tentes</a></li>                
                                    <li><a href="#">Podomètres et anémomètres</a></li>                
                                    <li><a href="#">Ski</a></li>                
                                    <li><a href="#">Surf</a></li>                
                                    <li><a href="#">Chaussures rando</a></li>                
                                    <li><a href="#">Sandales</a></li>                
                                    <li><a href="#">Sac de couchage</a></li>                
                                    <li><a href="#">Chaussures de ski</a></li>                
                                    <li><a href="#">Lampes frontales</a></li>                
                </ul><ul>                    <li><a href="#">Chaussures</a></li>                
                                    <li><a href="#">Sac à dos</a></li>                
                                    <li><a href="#">Accessoires</a></li>                
                                    <li><a href="#">Tentes</a></li>                
                                    <li><a href="#">Podomètres et anémomètres</a></li>                
                                    <li><a href="#">Ski</a></li>                
                                    <li><a href="#">Surf</a></li>                
                                    <li><a href="#">Chaussures rando</a></li>                
                                    <li><a href="#">Sandales</a></li>                
                                    <li><a href="#">Sac de couchage</a></li>                
                                    <li><a href="#">Chaussures de ski</a></li>                
                                    <li><a href="#">Lampes frontales</a></li>                
                </ul><ul>                    <li><a href="#">Chaussures</a></li>                
                                    <li><a href="#">Sac à dos</a></li>                
                                    <li><a href="#">Accessoires</a></li>                
                                    <li><a href="#">Tentes</a></li>                
                                    <li><a href="#">Podomètres et anémomètres</a></li>                
                                    <li><a href="#">Ski</a></li>                
                                    <li><a href="#">Surf</a></li>                
                                    <li><a href="#">Chaussures rando</a></li>                
                                    <li><a href="#">Sandales</a></li>                
                                    <li><a href="#">Sac de couchage</a></li>                
                                    <li><a href="#">Chaussures de ski</a></li>                
                                    <li><a href="#">Lampes frontales</a></li>                
                </ul><ul>                    <li><a href="#">Chaussures</a></li>                
                                    <li><a href="#">Sac à dos</a></li>                
                                    <li><a href="#">Accessoires</a></li>                
                                    <li><a href="#">Tentes</a></li>                
                                    <li><a href="#">Podomètres et anémomètres</a></li>                
                                    <li><a href="#">Ski</a></li>                
                                    <li><a href="#">Surf</a></li>                
                                    <li><a href="#">Chaussures rando</a></li>                
                                    <li><a href="#">Sandales</a></li>                
                                    <li><a href="#">Sac de couchage</a></li>                
                                    <li><a href="#">Chaussures de ski</a></li>                
                                    <li><a href="#">Lampes frontales</a></li>                
                </ul>  
            <li><a href="#">Sports de raquettes</a></li>
		<ul>                    <li><a href="#">Raquettes de tennis</a></li>                
                                    <li><a href="#">Balles</a></li>                
                                    <li><a href="#">Raquettes de squash</a></li>                
                                    <li><a href="#">Raquettes de badminton</a></li>                
                                    <li><a href="#">Accessoires</a></li>                
                                    <li><a href="#">Textiles</a></li>                
                                    <li><a href="#">Bagagerie</a></li>                
                                    <li><a href="#">Cordages</a></li>                
                                    <li><a href="#">Packages 2 raquettes de tennis</a></li>                
                </ul><ul>                    <li><a href="#">Raquettes de tennis</a></li>                
                                    <li><a href="#">Balles</a></li>                
                                    <li><a href="#">Raquettes de squash</a></li>                
                                    <li><a href="#">Raquettes de badminton</a></li>                
                                    <li><a href="#">Accessoires</a></li>                
                                    <li><a href="#">Textiles</a></li>                
                                    <li><a href="#">Bagagerie</a></li>                
                                    <li><a href="#">Cordages</a></li>                
                                    <li><a href="#">Packages 2 raquettes de tennis</a></li>                
                </ul><ul>                    <li><a href="#">Raquettes de tennis</a></li>                
                                    <li><a href="#">Balles</a></li>                
                                    <li><a href="#">Raquettes de squash</a></li>                
                                    <li><a href="#">Raquettes de badminton</a></li>                
                                    <li><a href="#">Accessoires</a></li>                
                                    <li><a href="#">Textiles</a></li>                
                                    <li><a href="#">Bagagerie</a></li>                
                                    <li><a href="#">Cordages</a></li>                
                                    <li><a href="#">Packages 2 raquettes de tennis</a></li>                
                </ul><ul>                    <li><a href="#">Raquettes de tennis</a></li>                
                                    <li><a href="#">Balles</a></li>                
                                    <li><a href="#">Raquettes de squash</a></li>                
                                    <li><a href="#">Raquettes de badminton</a></li>                
                                    <li><a href="#">Accessoires</a></li>                
                                    <li><a href="#">Textiles</a></li>                
                                    <li><a href="#">Bagagerie</a></li>                
                                    <li><a href="#">Cordages</a></li>                
                                    <li><a href="#">Packages 2 raquettes de tennis</a></li>                
                </ul>  
            <li><a href="#">Cycles</a></li>
		<ul>                    <li><a href="#">Vélos</a></li>                
                                    <li><a href="#">Accessoires</a></li>                
                                    <li><a href="#">Pièces détachées</a></li>                
                                    <li><a href="#">Diététique</a></li>                
                                    <li><a href="#">Massage et récupération</a></li>                
                </ul><ul>                    <li><a href="#">Vélos</a></li>                
                                    <li><a href="#">Accessoires</a></li>                
                                    <li><a href="#">Pièces détachées</a></li>                
                                    <li><a href="#">Diététique</a></li>                
                                    <li><a href="#">Massage et récupération</a></li>                
                </ul><ul>                    <li><a href="#">Vélos</a></li>                
                                    <li><a href="#">Accessoires</a></li>                
                                    <li><a href="#">Pièces détachées</a></li>                
                                    <li><a href="#">Diététique</a></li>                
                                    <li><a href="#">Massage et récupération</a></li>                
                </ul><ul>                    <li><a href="#">Vélos</a></li>                
                                    <li><a href="#">Accessoires</a></li>                
                                    <li><a href="#">Pièces détachées</a></li>                
                                    <li><a href="#">Diététique</a></li>                
                                    <li><a href="#">Massage et récupération</a></li>                
                </ul>  
Je suis conscient qu'il faut être motivé pour suivre mon pb, alors merci pour ceux qui pourront m'aider!

ViPHP
ViPHP | 5924 Messages

01 sept. 2008, 11:51

Il ne faut PAS faire n requêtes. Suit ce que je t'ai dit. Fait une seule requête et reconstruit l'arborescence en PHP. C'est quoi cette connerie de s'amuser à faire des requêtes dans des boucles ?

Bref, tu demandais une façon de faire, le minimum, c'est d'essayer de la suivre…

Invité
Invité n'ayant pas de compte PHPfrance

01 sept. 2008, 12:10

ok t'as raison, c'est pas très optimal. je vais revoir la méthode.
ya quelqu'un à coté de moi qui me parle de récursivité pour générer le menu quelque soit la profondeur. est-ce nécessaire? ta méthode implique t elle de la récursivité?

ViPHP
ViPHP | 5924 Messages

01 sept. 2008, 14:00

Non, ce n'est pas dans ce sens là que j'allais. Après ca dépend où est ce que tu las mets. Si tu la places au niveau de la base de données, c'est à dire que tu veux faire des requêtes récursivement, ce serait une inommable connerie, seul un chercheur en algorithmique pourrait sortir une solution comme cela…
Si tu la places au niveau du script PHP, oui, en effet, c'est une bonne idée, seulement il faut réussir à la mettre en place par rapport aux données que tu as. Par ailleurs, et surtout dans des langages très haut niveau comme PHP, là où on pourrait croire qu'une solution algorithmiquement parfaite est idéale, on peut arriver plus rapidement et plus facilement au même résultat avec les propriétés du langage. Dans la solution que je te propose, on tire partie de tableaux associatifs optimisés et des références…

Après si tu veux tester autre chose…

Invité
Invité n'ayant pas de compte PHPfrance

01 sept. 2008, 15:26

j'ai construit une requete qui me donne le var_dump suivant:
array(302) {
  [0]=>
  object(stdClass)(2) {
    ["category_parent_id"]=>
    string(1) "0"
    ["category_id"]=>
    }
  [1]=>
  object(stdClass)(2) {
    ["category_parent_id"]=>
    string(1) "0"
    ["category_id"]=>
   }
  [2]=>
  object(stdClass)(2) {
    ["category_parent_id"]=>
    string(1) "0"
    ["category_id"]=>
   }
}
Pas de pb pour le cas où le parent == 0 (premier niveau).
J'affiche tous les objets "catégorie" en faisant ceci, après la requete sql qui me sélectionne les enregistrements:
	foreach ($rows as $elt)
	{
		if ($elt->category_parent_id == 0) // condition d'affichage 1er niveau
		{
			echo "<li><a href='#'>" . $elt->category_name . "</a></li>";
		}
                               else //condition d'affichage sous menu
	}

Petite question sur le traitement des objets pour la condition d'affichage de sous menu:

avec la structure ci dessus, ya t il une fonction php qui permettrait de sélectionner tous les objets $elt dont la propriété "category_parent_id " vaut x par exemple?

Invité
Invité n'ayant pas de compte PHPfrance

02 sept. 2008, 00:57

Après quelques modifs et recherches, je reformule ma question car on s'y perd.
J'ai un tableau associatif comme ceci:
Array
(
    [0] => Array
        (
            [category_parent_id] => 0
            [category_child_id] => 1
            [category_id] => 1
            [vendor_id] => 1
            [category_name] => Montagne
            [category_description] => 
            [category_thumb_image] => 
            [category_full_image] => bf3a94d09cb29bddaa13839d184e1c5e.jpg
            [category_publish] => Y
            [cdate] => 1182523310
            [mdate] => 1199471607
            [category_browsepage] => browse_1
            [products_per_row] => 1
            [category_flypage] => shop.flypage
            [list_order] => 16
        )

    [1] => Array
        (
            [category_parent_id] => 0
            [category_child_id] => 2
            [category_id] => 2
            [vendor_id] => 1
            [category_name] => Sports de raquettes
            [category_description] => 
            [category_thumb_image] => 1e9f38247fc2d98c7a95d02aed200485.gif
            [category_full_image] => 
            [category_publish] => Y
            [cdate] => 1182523344
            [mdate] => 1203965763
            [category_browsepage] => browse_1
            [products_per_row] => 1
            [category_flypage] => shop.flypage
            [list_order] => 2
        )

    [2] => Array
        (
            [category_parent_id] => 1
            [category_child_id] => 3
            [category_id] => 3
            [vendor_id] => 1
            [category_name] => Cycles
            [category_description] => 
            [category_thumb_image] => 1e9f38247fc2d98c7a95d02aed200485.gif
            [category_full_image] => 
            [category_publish] => Y
            [cdate] => 1182523355
            [mdate] => 1188212355
            [category_browsepage] => browse_1
            [products_per_row] => 1
            [category_flypage] => shop.flypage
            [list_order] => 3
        )

    [3] => Array
        (
            [category_parent_id] => 1
            [category_child_id] => 4
            [category_id] => 4
            [vendor_id] => 1
            [category_name] => Sports collectifs
            [category_description] => 
            [category_thumb_image] => 1e9f38247fc2d98c7a95d02aed200485.gif
            [category_full_image] => 
            [category_publish] => Y
            [cdate] => 1182523369
            [mdate] => 1188212362
            [category_browsepage] => browse_1
            [products_per_row] => 1
            [category_flypage] => shop.flypage
            [list_order] => 9
        )
Ma question concerne la recherche dans les tableaux: comment faire pour récupérer tous les arrays qui contiennent [category_parent_id] => 1 ?
Il y en a 2 ici. Existe t-il évetuellement une fonction php qui peut me retourner tous les tableaux respectant la condition?