获取所有类别(多级)

Posted

技术标签:

【中文标题】获取所有类别(多级)【英文标题】:Get all categories (multilevel) 【发布时间】:2013-03-25 04:30:24 【问题描述】:

我正在使用 codeigniter,并且有一个包含 3 列(id、name、parent_id)的表。一个类别可以有很多子类别,一个子类别可以有很多子子类别。

我一直在尝试使用此代码获取所有类别及其子类别:

public function getCategory($id)

        $categories = array();
        while($id != 0)
        
                $this->db->from('categories'); //$this->table is a field with the table of categoris
                $this->db->where('id', $id);
                $this->db->limit(1);
                $result = $this->db->get()->row(); //fetching the result
                $categories[] = $result;
                $id = $result->parent_id;
        
        return $categories;


   public function getAllCategories()
    
            $this->db->select('id');
            $this->db->from('categories'); //$this->table is a field with the table of categoris
            $this->db->where('parent_id', 0);
            $mainCategories = $this->db->get()->result(); //fetching the result
            $result = array();
            foreach($mainCategories as $id)
            
                    $result[] = $this->getCategory($id->id);
            
            return $result;
    

但它只返回 1 级类别。

我的问题是如何完成我的任务:获取每个级别的所有类别和子类别。

【问题讨论】:

不要忘记将您的 codeigniter 答案标记为 php,您将获得更多帮助 ;) 这里没有递归。 Offtop:你尝试过使用其他结构吗?嵌套集,可能是?使用这种结构,您必须使用递归。 您好,请查看此链接,这是您问题的完美解决方案....phpsollutions.blogspot.com/2014/04/… 【参考方案1】:

解决问题的最简单方法是添加递归。

public function getCategoryTreeForParentId($parent_id = 0) 
  $categories = array();
  $this->db->from('categories');
  $this->db->where('parent_id', $parent_id);
  $result = $this->db->get()->result();
  foreach ($result as $mainCategory) 
    $category = array();
    $category['id'] = $mainCategory->id;
    $category['name'] = $mainCategory->name;
    $category['parent_id'] = $mainCategory->parent_id;
    $category['sub_categories'] = $this->getCategoryTreeForParentId($category['id']);
    $categories[$mainCategory->id] = $category;
  
  return $categories;

这种方法可以通过预加载所有类别并对数组进行操作来大大提高速度,从而跳过对每个新 parent_id 的查询。

我也没有使用 codeigniter 的对象,因为我不认识它们。如果它们支持魔法设置器/获取器或者可以被说服采用一组子对象,则应该使用它们来代替我在这里构建的数组。

该算法的作用是:加载具有给定 parent_id 的所有类别,循环遍历所有这些类别,假设迭代类别 ID 为 parent_id 并为其加载所有内容。 这有效地加载所有类别,只要它们引用现有类别。

这涉及到一个小危险:当您构建类别 A 和 B,其中 A 有 B 作为父级,B 有 A 作为父级时,您将陷入无限循环,因为它们一次又一次地相互加载。这会迫使您在数据中拥有一个干净的树结构。

更新

因为这仍然得到了赞成: 关于此实现还有另一个建议。 如果您的类别树更大或有多个级别,您可能会遇到性能问题,因为此实现会使用新的查询参数一次又一次地加载类别。这很容易导致数十、数百或数千个查询,具体取决于您的类别树。

一种更有效的方法是从您的类别表中加载 所有 类别(使用一个查询),并在您的应用程序中使用递归对它们进行排序。这是极少数情况之一,早期评估确实可以提高性能。

如果在同一个请求中多次需要树,甚至可以通过静态变量添加缓存(具有缓存的所有常见危险)。

【讨论】:

感谢您返回我需要的数组。但是我应该如何处理这些数据,因为我需要在 中设置类别的样式。我应该使用什么循环以及如何使用? 这又是一个递归函数。数据具有树的形式,其中每个节点可以有更多的孩子。一个循环可以只遍历一个平面数组。所以这个新的递归函数需要打开一个ul,遍历孩子,为每个孩子打开一个li标签,为孩子调用递归函数,为孩子关闭li标签,(在循环)关闭ul 标签并返回。也许它也应该在某处打印一些信息。 多级类别多选 CodeIgniter github.com/hamedhossani/… 你太棒了!!!谢谢大佬。【参考方案2】:

我将提供一个不同的解决方案,尽管您需要进行一些轻微的重组:

使用沿袭风格的层次结构,您可以避免所有递归问题并更快地提取数据。您使用完整的祖先列表标记每个类别,例如:0001-0005-0015 ... 等,然后可以使用 LIKE 运行简单查询以获取您的子查询。

我有一个关于 git 的 Codeigniter 库和博客文章,解释了它是如何工作的:http://codebyjeff.com/blog/2012/10/nested-data-with-mahana-hierarchy-library

【讨论】:

【参考方案3】:

这是一个 codeigniter 库,我在 *** 的答案中找到了它,但我不记得它的所有者。我对其进行了一些修改,以将嵌套类别作为列表返回。它对我很有效。

<?php
if (!defined('BASEPATH'))
    exit('No direct script access allowed');
class Tree 

    var $table = '';
    var $CI = '';
    var $ul_class = '';
    var $iteration_number = 0;
    function Tree($config = array()) 
        $this -> table = $config['table'];
        $this -> CI = &get_instance();
        $this -> CI -> load -> database();
        $this -> ul_class = $config['ul_class'];
    

    function getTree($parent_id = 1) 
        $this -> iteration_number++;
        $this -> CI -> db -> where('parent_id', $parent_id);
        $first_level = $this -> CI -> db -> get($this -> table) -> result();
        if($this->iteration_number == 1)
            $tree = '<ul id="red" class="' . $this -> ul_class . '">';
        else
            $tree = '<ul>';
        foreach ($first_level as $fl) 
            $this -> CI -> db -> where('parent_id', $fl -> category_id);
            $count = $this -> CI -> db -> count_all_results($this -> table);
            if ($count != 0) 
                $tree .= '<li><span>' . $fl -> category_name . '</span>';
                $tree .= $this -> getTree($fl -> category_id);
             else 
                $tree .= '<li><a href="'.base_url().'categories/sub/'.str_replace(' ', '-', $fl -> category_name).'" cat_id="'.$fl -> category_id.'" class="leaf">' . $fl -> category_name . '</a>';
            
            $tree .= '</li>';
        
        $tree .= '</ul>';
        return $tree;
    

 ?>

您可以从控制器中使用它,如下所示:

$config['ul_class']='treeview';
$config['table']='categories';
$this->load->library('tree',$config);
$tree = $this->tree->getTree();

DB表结构如下:

CREATE TABLE IF NOT EXISTS `categories` (
  `category_id` int(4) NOT NULL AUTO_INCREMENT,
  `category_name` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
  `category_description` varchar(500) COLLATE utf8_unicode_ci NOT NULL,
  `parent_id` int(4) NOT NULL,
  PRIMARY KEY (`category_id`),
  KEY `categories_categories_fk_idx` (`parent_id`)
) ENGINE=InnoDB 

你可以通过库中的getTree函数修改返回的结果,返回你需要的。

【讨论】:

【参考方案4】:

假设您的***类别的 parent_id = 0。 您可以使用以下代码从数据库中获取数据,并创建一个二维数组

$this->db->from('categories');
$query = $this->db->get();
$rows = $query->result()) 
// ok, we have an array ($rows). We need it
// transformed into a tree
$categories = array();
foreach ($rows as $category) 
   // add the category into parent's array
   $categories[$category->parent_id][] = $category;
    
return $categories;

然后您可以遍历 $categories 数组,假设 $categories[0] 是一个包含***类别的数组,并且 $categories[$i] 包含 id = 的类别(或子类别)的子类别$i。

【讨论】:

以上是关于获取所有类别(多级)的主要内容,如果未能解决你的问题,请参考以下文章

大量多级分类数据的获取缓存搜索查询 怎么设计最快 ?

如何获取所有类别和子类别?

获取总类别树(所有类别及其子类别的列表)与根据需要获取每个分支?

获取 WooCommerce 中的所有产品类别

Laravel 获取所有类别的帖子数

MYSQL - 获取所有选定类别中的行