سؤال

لقد قرأت الكثير من الأشخاص الذين يناقشون قوائم متداخلة، لكنني كنت أتساءل كيفية التكرار من خلال قائمة / شجرة مجاورة في PHP.

لدي طاولة مع: معرف، العنوان، Parent_id

ولقد اخترت جميع السجلات في صفيف يسمى صفحات $.

ثم باستخدام هذا 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>";
    }
}

هذا النوع من الأعمال ولكن في نهاية المطاف مع أي قائمة فرعية تتكرر على سبيل المثال

  • الصفحة الرئيسية
    • أخبار
      • الأخبار الفرعية
    • مقالات
      • شرط
  • أخبار
    • الأخبار الفرعية
  • مقالات
    • شرط
  • الأخبار الفرعية
  • شرط

لقد حاولت إضافة المعرف الحالي إلى صفيف يتم تمريره عبر الوظيفة، ثم باستخدام In_Array للتحقق مما إذا كان هناك، لكنني لم يكن لدي أي فرح تفعل ذلك.

أي مساعدة سيكون محل تقدير كبير.

أحتاج إلى تحليل الشجرة بأكملها حتى اختيار الوالد كما 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>';
    }
}

لتخزينها أكثر شجرة مثلك قد ترغب في النظر إلى هذا الموقع: تخزين البيانات الهرمية في قاعدة بيانات.

نصائح أخرى

إذا قمت بإنشاء صفيف من الصفحات التي تم تجمعها بواسطة المعرف الأصل، فمن السهل جدا إنشاء القائمة بشكل متكرر. سيطلب هذا فقط استعلام قاعدة بيانات واحدة.

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

أين توجد صفحة $ من؟ قد يكون لديك مشكلة عدم حصانة حقن SQL في التعليمات البرمجية الخاصة بك إذا لم تكن فرزها أو استخدام عبارة مستعدة.

أيضا بيان 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

استبدال "؟" في السطر الثاني مع معرف صفحة البداية.

سيكون أبسط الإصلاح فقط، عندما تقوم بتحديد الاختيار الأولية $pages (عدم إظهاره)، أضف بند عند:

WHERE pag_parent = 0

(أو لاغيا، اعتمادا على كيفية تخزين الصفحات "المستوى الأعلى").

بهذه الطريقة لن تختار جميع الأطفال في البداية.

عندما يصبح هذا الجدول كبيرا، يمكن أن تصبح العودية غير عملي. كتبت منشور مدونة عن طريقة أقل recursion: http://www.alandelevie.com/2008/07/07/12/Recursion-Storage-of-hierarchical-data-in-a-relational-database/

العثور على أفضل الوالد، وجميع الآباء والأمهات، وجميع الأطفال من العقدة (تحسينات إجابة توم هاغ):

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