GORAGOD.com

การ query และการจัดการแสดงผลในรูปแบบ tree

มีคำถามบน Facebook เกี่ยวกับการ query และ แสดงผลในแบบ tree โดยมีรูปแบบข้อมูลที่จัดเก็บตามรูป
 
หลักเกณฑ์ก็คือ parent_id จะทำการเก็บ id ของรายการที่ระดับที่สูงกว่า ซึ่งโจทย์สามารถมีระดับลูกได้แบบไม่จำกัด

แนวคิดจริงๆผมแนะนำให้ทำการ query ในแต่ละระดับออกมาแสดงผล เช่นในครั้งแรกเราจะ query เอาเฉพาะที่ parent_id เป็น 0 ออกมาแสดงก่อน เพราะมันคือระดับแรกสุด จากนั้นเมื่อมีการคลิกที่แต่ละรายการค่อยไปโหลดเอารายการที่มี parent_id ตรงกับรายการที่คลิกมาแสดงผล ซึ่งเป็นวิธีที่มีประสิทธิภาพที่สุด เนื่องจากหากมีข้อมูลจำนวนมาก การพยายาม query รายการทั้งหมดมาแสดงอาจสาหัสก็ได้

แต่เนื่องจากโจทย์ต้องการ query ข้อมูลออกมาทั้งหมด ผมเลยแนะนำวิธีข้างล่างนี้ครับ

 $datas = array();
 $pointer = array();
 $sql = "SELECT `id`,`parent_id`,`name` FROM `test` ORDER BY `id`,`parent_id`";
 foreach ($db->customQuery($sql) AS $item) {
  if ($item['parent_id'] == 0) {
   // รายการระดับแรก
   $datas[$item['id']] = $item;
   // ใช้ตัวแปร pointer เก็บตำแหน่งตาม id
   $pointer[$item['id']] = &$datas[$item['id']];
  } else {
   // รายการลูกจะเพิ่มไปที่ pointer ของระดับก่อนหน้า
   $pointer[$item['parent_id']]['childs'][$item['id']] = $item;
   $pointer[$item['id']] = &$pointer[$item['parent_id']]['childs'][$item['id']];
  }
 }
// print_r($datas); // ตรวจสอบผลลัพท์
 // วนลูปเพื่อแสดงผลรายการระดับแรก
 foreach ($datas AS $values) {
  show_result($values, 0);
 }
 // ฟังก์ชั่นจัดการแสดงผล
 function show_result($datas, $level) {
  // แสดงผล
  echo str_repeat('&nbsp;&nbsp;', $level).$datas['name'].'<br>';
  if (isset($datas['childs'])) {
   foreach ($datas['childs'] AS $values) {
    show_result($values, $level + 1);
   }
  }
 }

วิธีคิดในการ query แบบนี้คือการ query ข้อมูลทั้งหมดออกมาเลยครั้งเดียว (เหมาะกับข้อมูลที่มีจำนวนไม่มาก) โดยเรียงลำดับตาม id และ parent_id หลังจากนั้น ก็เอาข้อมูลทั้งหมดมาใส่ array $datas แล้วค่อยเอามาแสดงผลอีกที โดยที่ตัวอย่างนี้ผมใช้ตัวแปร pointer เก็บข้อมูลรายการต่างๆเพื่อใช้ในการอ้างอิง รายการในระดับที่สูงกว่า
ผลลัพท์
one
  four
    six
    seven
  five
two
  three
    eight
      nine
        ten