2

我正在尝试为父子类别制作未排序列表,如果有任何子类别,它将创建另一个未排序列表(如缩进文本),以便用户可以正确理解。

我有 fetch sql 但对于 foreach 我不明白如何设置,因此通过在父类别下创建另一个无序列表,子类别将仅显示在父类别下。

这是我的代码

$query_cat =    "SELECT * FROM ^categories";
$query = qa_db_query_sub($query_cat);
$catsid = qa_db_read_all_assoc($query);

echo '<UL>';
foreach ($catsid as $catid){
    echo '<LI>'. $catid['title'].' '. $catid['categoryid'].'</LI>';
}
echo '</UL>';

类别的表格图像

所以最终的结果是

  • 第一类
    • 子类别1
  • 第二类

编辑:

使用@vlcekmi3 修改代码后回答https://stackoverflow.com/a/13451136/1053190我得到了这个结果

在此处输入图像描述

现在如何从父列表中排除子类别?

4

2 回答 2

1

你可以使用复杂的查询或类似的东西

foreach ($catsid as $catid) {
    ...
    $subquery_cat = "SELECT * FROM ^categories WHERE parentid='".$catid['categoryid']."'";
    $query = qa_db_query_sub($subquery_cat);
    $subcatsid = qa_db_read_all_assoc($query);
    // wrap into html
    ...
}
于 2012-11-19T09:42:53.593 回答
1

您的设计没有真正简单的解决方案。最有效的方法是添加类似order_in_list(也许是depth_in_list)的列。

它们将在循环中预先计算(伪代码):

START TRANSACTION
UPDATE t1 SET order_in_list = 0 // Restart whole loop

$ids = array(0);

while $id = array_shift($ids){
   $record = SELECT * FROM t1 WHERE id = $id // Get id details, order_in_list is important
   $children = SELECT * FROM t1 WHERE parent_id = $id // get list of all childs
   // If it's root element, start indexing from 0
   $root_order = ($record ? $record->order_in_list : 1) 
   $child_no = count($children) // How many child will be adding

   // No children, nothing to do:
   if $child_no < 1{
      continue;
   }

   append_to_array($ids, $children) // Store ids to process

   // Shift all later records, we'll be creating gap in order_in_list 1,2,3,4,5
   // To 1,2,5,6,7 to insert items on places 3,4
   UPDATE t1 SET order_in_list = (order_in_list + $child_no)
      WHERE order_in_list > $record->order_in_list

   // Okay, set IDs for direct children
   foreach( $children as $child){
       UPDATE t1 SET order_in_list = $root_order, depth_in_list = $record->depth_in_list+1
          WHERE id = $child->id
       $root_order++;
   }
}
COMMIT

这样,您将获得以下记录:

First category, 1, 1
Second category 3, 1
Sub category, 2, 2

您可以使用简单的循环显示:

$last_depth = 0;
foreach( (SELECT * FROM t1 ORDER by `order_in_list`) as $row){
    if( $last_detph > $row['depth_in_list'])){
       // Close level </ul>
    } else if($last_detph < $row['depth_in_list']){
       // Opening level <ul>
    } else {
       // The same depth
    }
    $last_depth = $row['depth_in_list'];
}


不修改数据库

构建两个包含根元素和所有元素的数组可能是最有效的:

$root_elements = array();
$all_elements = array();

foreach( (SELECT * FROM t1) as $row){
    // Store details into all_elements, note that entry may have already be created when
    // processing child node
    if( isset( $all_elements[$row['id']])){
      // set details
    } else {
      $all_elements[$row['id']] = $row;
      $all_elements[$row['id']]['children'] = array(); // Array of child elements
    }

    if( $row['parent_id'] == NULL){
        $all_elements[] = $row['id'];  // Add row element
    } else {
        if( isset( $all_elements[ $row[ 'parent_id']])){
            $all_elements[ $row[ 'parent_id']]['children'][] = $row['id'];
        } else {
            // Create new record:
            $all_elements[ $row[ 'parent_id']] = array();
            $all_elements[ $row[ 'parent_id']]['children'] = array($row['id']);
        }
    }
}

然后写成:

foreach( $root_elements as $element_id){
    write_recursive( $all_elements[ $element_id]);
}

// And display
function write_recursive( $element)
{
   echo '<ul>...';
   if( count( $element['children'])){
      foreach( $element['children'] as $child){
         write_recursive( $all_elements[ $child]);
      }
   }
   echo '</ul>';
}

您最好为此创建类(以使用全局变量替换),但您应该有一种可靠的方法来做到这一点。无论如何,尽量避免在大量记录中使用它(我不会超过 2000-5000 个菜单条目),至少尝试缓存它。

注意:解决方案在显示列表时面向数据库上的最少请求数。

于 2012-11-19T09:45:00.947 回答