Question

J'ai lu beaucoup de personnes discutant des listes imbriquées, mais je me demandais comment itérer une liste de adjacancy / arbre en PHP.

J'ai une table avec: id, titre, id_parent

Et j'ai choisi tous les documents sur dans un tableau appelé pages $.

Ensuite, en utilisant ce php:

function makeList($pages, $used) {
    if (count($pages)) {
        echo "<ul>";
        foreach ($pages as $page) {
            echo "<li>".$page['pag_title'];
            $par_id = $page['pag_id'];
            $subsql("SELECT * FROM pages WHERE pag_parent = ".$par_id."");

            // running the new sql through an abstraction layer
            $childpages = $dbch->fetchAll();
            makeList($childpages, $used, $lastused);
            echo "</li>";
        }
        echo "</ul>";
    }
}

Ce genre de travaux, mais je finis avec un sous-menu étant répété par exemple.

  • Accueil
    • Nouvelles
      • Sous-nouvelles
    • Articles
      • Article
  • Nouvelles
    • Sous-nouvelles
  • articles
    • article
  • Sous-nouvelles
  • article

Je l'ai essayé d'ajouter l'identifiant courant dans un tableau qui est passé par la fonction, puis en utilisant in_array pour vérifier si elle est là, mais je n'ai pas eu la joie de faire cela.

Toute aide serait très apprécié.

Je dois analyser tout l'arbre afin de choisir des parents comme 0 est pas une option

Était-ce utile?

La solution

Comme il le fait déjà le SQL, vous ne devez pas le faire à l'extérieur avant le premier appel de fonction.

function makeList($par_id = 0) {
    //your sql code here
    $subsql("SELECT * FROM pages WHERE pag_parent = $par_id");
    $pages = $dbch->fetchAll();

    if (count($pages)) {
        echo '<ul>';
        foreach ($pages as $page) {
            echo '<li>', $page['pag_title'];
            makeList($page['pag_id']);
            echo '</li>';
        }
        echo '</ul>';
    }
}

Pour le stockage plus arbre comme vous voudrez peut-être regarder ce site: Stockage Les données hiérarchiques dans une base de données.

Autres conseils

Si vous créez un tableau de pages groupées par id parent, il est assez facile de construire récursive la liste. Cela ne nécessitera une requête de base de données.

<?php

 //example data
 $items = array(
    array('id'=>1, 'title'=>'Home', 'parent_id'=>0),
    array('id'=>2, 'title'=>'News', 'parent_id'=>1),
    array('id'=>3, 'title'=>'Sub News', 'parent_id'=>2),
    array('id'=>4, 'title'=>'Articles', 'parent_id'=>0),
    array('id'=>5, 'title'=>'Article', 'parent_id'=>4),
    array('id'=>6, 'title'=>'Article2', 'parent_id'=>4)
 );

 //create new list grouped by parent id
 $itemsByParent = array();
 foreach ($items as $item) {
    if (!isset($itemsByParent[$item['parent_id']])) {
        $itemsByParent[$item['parent_id']] = array();
    }

    $itemsByParent[$item['parent_id']][] = $item;
 }

 //print list recursively 
 function printList($items, $parentId = 0) {
    echo '<ul>';
    foreach ($items[$parentId] as $item) {
        echo '<li>';
        echo $item['title'];
        $curId = $item['id'];
        //if there are children
        if (!empty($items[$curId])) {
            makeList($items, $curId);
        }           
        echo '</li>';
    }
    echo '</ul>';
 }

printList($itemsByParent);

Où se trouve la page $ vient? Vous pourriez avoir une vulnérabilité d'injection SQL dans votre code si vous n'êtes pas échapper ou en utilisant une déclaration préparée.

En outre l'instruction SELECT dans une boucle saute comme une mauvaise pratique. Si la table est pas grande, puis sélectionnez le contenu de la table entière, puis itérer le jeu de résultats en PHP pour construire la structure de données d'arbre. Cela pourrait prendre jusqu'à n * (n-1) / 2 itérations dans le cas pathologique de votre arbre étant une liste chaînée. Arrêtez lorsque tous les noeuds ont été ajoutés à l'arbre, ou le nombre de nœuds restants reste le même d'une itération à l'autre -. Cela signifie que les nœuds restants ne sont pas les enfants de votre nœud racine

Par ailleurs, si votre base de données prend en charge les requêtes SQL récursives, vous pouvez l'utiliser, et il ne sélectionnera que les nœuds qui sont des enfants de votre nœud parent. Vous aurez encore à construire le même objet arbre en PHP. La forme de la requête serait quelque chose comme:

WITH temptable(id, title, parent_id) AS (
  SELECT id, title, parent_id FROM pages WHERE id = ?
  UNION ALL
  SELECT a.id, a.title, a.parent_id FROM pages a, temptable t
   WHERE t.parent_id = a.id
) SELECT * FROM temptable

Remplacez le '?' sur la deuxième ligne avec l'ID de page de démarrage.

La solution la plus simple serait juste, ajouter une clause WHERE comme lorsque vous faites la sélection initiale pour définir $pages (que vous ne présentez pas):

WHERE pag_parent = 0

(ou IS NULL, selon la façon dont vous stockez les pages "haut niveau").

De cette façon, vous ne choisirez pas tous les enfants d'abord.

Quand cette table devient grand, récursivité peut obtenir difficile à manier. J'ai écrit un blog sur une méthode de récursivité moins: http://www.alandelevie.com/2008/07/12/recursion-less-storage-of-hierarchical-data-in-a-relational-database/

Trouver top parent, tous les parents et tous les enfants d'un noeud (améliorations pour la réponse de Tom Haigh):

<?php

 //sample data (can be pulled from mysql)
 $items = array(
    array('id'=>1, 'title'=>'Home', 'parent_id'=>0),
    array('id'=>2, 'title'=>'News', 'parent_id'=>1),
    array('id'=>3, 'title'=>'Sub News', 'parent_id'=>2),
    array('id'=>4, 'title'=>'Articles', 'parent_id'=>0),
    array('id'=>5, 'title'=>'Article', 'parent_id'=>4),
    array('id'=>6, 'title'=>'Article2', 'parent_id'=>4)
 );

 //create new list grouped by parent id
 $itemsByParent = array();
 foreach ($items as $item) {
    if (!isset($itemsByParent[$item['parent_id']])) {
        $itemsByParent[$item['parent_id']] = array();
    }

    $itemsByParent[$item['parent_id']][] = $item;
 }

 //print list recursively 
 function printList($items, $parentId = 0) {
    echo '<ul>';
    foreach ($items[$parentId] as $item) {
        echo '<li>';
        echo $item['title'];
        $curId = $item['id'];
        //if there are children
        if (!empty($items[$curId])) {
            printList($items, $curId);
        }           
        echo '</li>';
    }
    echo '</ul>';
 }

printList($itemsByParent);


/***************Extra Functionality 1****************/

function findTopParent($id,$ibp){


    foreach($ibp as $parentID=>$children){ 

            foreach($children as $child){


            if($child['id']==$id){


             if($child['parent_id']!=0){

            //echo $child['parent_id'];
            return findTopParent($child['parent_id'],$ibp);

          }else{ return $child['title'];}

         }              
        }
}
}

$itemID=7;  
$TopParent= findTopParent($itemID,$itemsByParent);





/***************Extra Functionality 2****************/

function getAllParents($id,$ibp){ //full path

foreach($ibp as $parentID=>$nodes){ 

    foreach($nodes as $node){

        if($node['id']==$id){

             if($node['parent_id']!=0){

                $a=getAllParents($node['parent_id'],$ibp);
                array_push($a,$node['parent_id']);
                return $a;

              }else{
                    return array();
                  }

             }
    }
}
}


$FullPath= getAllParents(3,$itemsByParent);
print_r($FullPath);

/*
Array
(
[0] => 1
[1] => 2
)
*/

/***************Extra Functionality 3****************/

 //this function gets all offspring(subnodes); children, grand children, etc...
 function getAllDescendancy($id,$ibp){

 if(array_key_exists($id,$ibp)){

         $kids=array();
         foreach($ibp[$id] as $child){

            array_push($kids,$child['id']);

            if(array_key_exists($child['id'],$ibp))

$kids=array_merge($kids,getAllDescendancy($child['id'],$ibp));

             }

         return $kids;       

     }else{
            return array();//supplied $id has no kids
          }
 }

print_r(getAllDescendancy(1,$itemsByParent));
/*
Array
(
[0] => 2
[1] => 3
)
*/


print_r(getAllDescendancy(4,$itemsByParent));
/*
Array
(
[0] => 5
[1] => 6
)
*/


print_r(getAllDescendancy(0,$itemsByParent));
/*
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
[4] => 5
[5] => 6
)

*/

?>
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top