문제

중첩 목록에 대해 논의하는 많은 사람들을 읽었지만 PHP에서 인접 목록/트리를 반복하는 방법이 궁금합니다.

나는 다음과 같은 테이블을 가지고 있습니다 :ID, 제목, parent_id

그리고 모든 레코드를 $pages라는 배열로 선택했습니다.

그런 다음 이 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>";
    }
}

이런 종류의 작업은 가능하지만 하위 메뉴가 반복됩니다.

    • 소식
      • 하위 뉴스
    • 조항
      • 기사
  • 소식
    • 하위 뉴스
  • 조항
    • 기사
  • 하위 뉴스
  • 기사

함수를 통해 전달되는 배열에 현재 ID를 추가한 다음 in_array를 사용하여 해당 ID가 있는지 확인하려고 시도했지만 그렇게 하는 것이 즐겁지 않았습니다.

어떤 도움이라도 주시면 감사하겠습니다.

전체 트리를 구문 분석해야 하므로 부모를 0으로 선택하는 것은 옵션이 아닙니다.

도움이 되었습니까?

해결책

이미 SQL을 수행하므로 첫 번째 기능 호출 전에 외부에서 수행 할 필요가 없습니다.

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

이 사이트를보고 싶을 수도 있습니다. 데이터베이스에 계층 적 데이터를 저장합니다.

다른 팁

Parent ID로 그룹화 된 페이지 배열을 작성하면 목록을 재귀 적으로 빌드하기가 매우 쉽습니다. 데이터베이스 쿼리 만 있으면됩니다.

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

$page는 어디에서 오는가?이스케이프 처리하지 않거나 준비된 문을 사용하지 않는 경우 코드에 SQL 주입 취약점이 있을 수 있습니다.

또한 for 루프 내부의 SELECT 문은 나쁜 습관으로 드러납니다.테이블이 그다지 크지 않으면 전체 테이블의 내용을 선택한 다음 PHP에서 결과 세트를 반복하여 트리 데이터 구조를 구축합니다.트리가 연결된 목록인 병리학적 경우에는 최대 n*(n-1)/2번의 반복이 필요할 수 있습니다.모든 노드가 트리에 추가되었거나 남은 노드 수가 한 반복에서 다음 반복까지 동일하게 유지되면 중지합니다. 이는 나머지 노드가 루트 노드의 하위 노드가 아님을 의미합니다.

또는 데이터베이스가 재귀 SQL 쿼리를 지원하는 경우 이를 사용할 수 있으며 상위 노드의 하위 노드만 선택됩니다.여전히 PHP에서 트리 개체를 직접 만들어야 합니다.쿼리 형식은 다음과 같습니다.

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

'?'를 대체하십시오. 시작 페이지 ID가있는 두 번째 줄에서.

가장 간단한 수정은 초기 선택을 할 때입니다. $pages (표시하지 않는), 다음과 같은 위치를 추가하십시오.

WHERE pag_parent = 0

(또는 "최상위"페이지를 저장하는 방법에 따라 NULL입니다).

그렇게하면 처음에 모든 어린이를 선택하지 않을 것입니다.

그 테이블이 커지면 재귀는 다루기 어려울 수 있습니다. 재귀가없는 방법에 대한 블로그 게시물을 썼습니다. http://www.alandelevie.com/2008/07/12/recursion-less-storage-of-hierarchical-in-a-relational-database/

최고 부모, 모든 부모 및 노드의 모든 자녀를 찾는 것 (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
)

*/

?>
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top