Pergunta

Eu li um monte de pessoas discutindo listas aninhadas, mas eu queria saber como percorrer uma lista adjacancy / árvore em PHP.

Eu tenho uma tabela com: id, título, parent_id

E eu selecionei todos os registros fora em uma matriz chamada $ páginas.

Em seguida, usando esse 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>";
    }
}

Este tipo de obras, mas eu acabar com qualquer sub-menu que está sendo repetida por exemplo.

  • Home
    • Notícias
      • Sub-news
    • artigos
      • artigo
  • Notícias
    • Sub-news
  • artigos
    • artigo
  • Sub-news
  • artigo

Eu tentei adicionar o ID atual em uma matriz que é passada através da função, e em seguida, usando in_array para verificar se ele está lá, mas eu não tinha a fazer alegria que.

Qualquer ajuda seria muito apreciada.

Eu preciso para analisar a árvore inteira de modo a escolher pais como 0 não é uma opção

Foi útil?

Solução

Uma vez que já faz o SQL, você não tem que fazê-lo fora antes da primeira chamada de função.

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>';
    }
}

Para armazená-lo mais árvore como você pode querer olhar para este site: Armazenamento dados hierárquicos em um banco de dados.

Outras dicas

Se você criar uma matriz de páginas agrupadas por id do pai é muito fácil de construir de forma recursiva lista. Isso só vai exigir uma consulta de banco de dados.

<?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);

Onde está o $ page vindo? Você pode ter uma vulnerabilidade de injeção SQL em seu código se você não está escapando-lo ou usando uma declaração preparada.

Além disso, a instrução SELECT dentro de um loop for salta como uma prática ruim. Se a tabela não é tão grande, em seguida, selecione o conteúdo de toda a tabela e, em seguida, percorrer a conjunto de resultados no PHP para construir a estrutura de dados árvore. Isso poderia levar até n * (n-1) / 2 iterações no caso patológico de sua árvore sendo uma lista ligada. Parar quando todos os nós tiverem sido adicionados à árvore, ou o número de nós restantes permanece o mesmo de uma iteração para a próxima -. Isto significa que os nós restantes não são filhos de seu nó raiz

Como alternativa, se o seu banco de dados suporta recursiva consultas SQL, você pode usar isso, e ele só irá selecionar os nós que são filhos de seu nó pai. Você ainda terá que construir o objeto árvore se em PHP. A forma da consulta seria algo como:

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

Substitua o '?' na segunda linha com o ID da página inicial.

A correção mais simples seria apenas, quando você está fazendo a seleção inicial para set $pages (que você não mostrar), adicionar uma cláusula WHERE como:

WHERE pag_parent = 0

(ou IS NULL, dependendo de como você está armazenando páginas de "nível superior").

Dessa forma, você não vai selecionar todas as crianças inicialmente.

Quando essa tabela se torna grande, recursão pode obter complicado. Eu escrevi um post sobre um método recursão-less: http://www.alandelevie.com/2008/07/12/recursion-less-storage-of-hierarchical-data-in-a-relational-database/

Finding topo pai, todos os pais e todos os filhos de um nó (melhorias para a resposta 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
)

*/

?>
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top