【问题标题】:How to create a nested-list of categories in Laravel?如何在 Laravel 中创建类别的嵌套列表?
【发布时间】:2021-06-12 16:26:56
【问题描述】:

如何在 Laravel 中创建嵌套的类别列表?

我想创建这样的东西:

  • --- PHP
  • ----- Laravel
  • --------- 版本
  • ------------ V 5.7
  • --- Python
  • ----- 姜戈
  • --- 红宝石
  • ........

我的类别表的字段是:

id | name | parent_id

如果我必须添加另一列,例如深度之类的,请告诉我。

我正在使用以下代码,但我认为这不是最好的解决方案。此外,我不能将此函数传递给我的视图。

function rec($id)
{
     $model = Category::find($id);
     foreach ($model->children as $chield) rec($chield->id);
     return $model->all();
}

function main () {
    $models = Category::whereNull('parent_id')->get();
    foreach ($models as $parent) return rec($parent->id);
}

【问题讨论】:

    标签: php laravel nested-lists


    【解决方案1】:

    您可以制作一个自引用模型:

    class Category extends Model {
    
        public function parent()
        {
            return $this->belongsTo('Category', 'parent_id');
        }
    
        public function children()
        {
            return $this->hasMany('Category', 'parent_id');
        }
    }
    

    并建立递归关系:

    // recursive, loads all descendants
    public function childrenRecursive()
    {
       return $this->children()->with('childrenRecursive');
    }
    

    让父母带着他们所有的孩子:

    $categories = Category::with('childrenRecursive')->whereNull('parent_id')->get();
    

    最后,您只需要遍历孩子,直到孩子为空。如果您不小心,肯定会出现一些性能问题。如果这是一个相当小的数据集,您打算保持这种状态,那应该不是问题。如果这将是一个不断增长的列表,那么有一个 root_parent_id 或一些可以查询并手动组装树的东西可能是有意义的。

    【讨论】:

    • 这太棒了,谢谢 :) 架构非常好,绝对有助于保存内存
    • 很高兴能帮上忙!
    • @AlexHarris 我们如何使用嵌套类别进行分页?
    • 你如何在刀片中以最有效的方式循环?说只做一个嵌套的<ul> 提前谢谢。顺便说一句,这是一个很棒的主意!
    【解决方案2】:

    如果有人需要更好的答案,请查看我的答案,当我遇到这样的问题时,它对我很有帮助。

       class Category extends Model {
    
         private $descendants = [];
    
         public function subcategories()
            {
              return $this->hasMany(Category::class, 'parent_id');
            }
    
         public function children()
            {
                return $this->subcategories()->with('children');
            }
    
         public function hasChildren(){
                if($this->children->count()){
                    return true;
                }
        
                return false;
            }
    
         public function findDescendants(Category $category){
                $this->descendants[] = $category->id;
        
                if($category->hasChildren()){
                    foreach($category->children as $child){
                        $this->findDescendants($child);
                    }
                }
            }
        
          public function getDescendants(Category $category){
                $this->findDescendants($category);
                return $this->descendants;
            }
     }
    

    然后在你的控制器中测试一下:

    $category = Category::find(1);
    $category_ids = $category->getDescendants($category);
    

    它将在数组中生成 id=1 的您的类别的所有后代。 然后:

    $products = Product::whereIn('category_id',$category_ids)->get();
    

    不客气 =)

    【讨论】:

    • 在你的代码中你有:return $this->subcategories()->with('children'),但是,你没有任何方法 subcategories()。要么你是从别人那里借来的代码,要么这会坏掉。
    • @Vladd 感谢您的关注。我更新了我的答案:添加了关系函数 subcategories()。如果你在人际关系中遇到问题,可以阅读更多关于 Laravel 的人际关系laravel.com/docs/8.x/eloquent-relationships
    • 我没有遇到任何问题。只是指出您的代码不完整,因此不应该发布,我什至没有尝试过,只是通过阅读我发现它不起作用。我的温馨建议是不要发布没有检查3次且不完整的东西。
    • @Vladd,我认为没有必要,stackoverflow 不是学习资源。我的目标不是实现全部功能,而是要回答问题。
    • 像黄油一样工作 :) 干得好。
    【解决方案3】:

    此函数将返回树数组:

    function getCategoryTree($parent_id = 0, $spacing = '', $tree_array = array()) {
        $categories = Category::select('id', 'name', 'parent_id')->where('parent_id' ,'=', $parent_id)->orderBy('parent_id')->get();
        foreach ($categories as $item){
            $tree_array[] = ['categoryId' => $item->id, 'categoryName' =>$spacing . $item->name] ;
            $tree_array = $this->getCategoryTree($item->id, $spacing . '--', $tree_array);
        }
        return $tree_array;
    }
    

    【讨论】:

      【解决方案4】:

      在这个领域以某种方式搜索我想分享一个获取孩子深度级别的功能:

          function getDepth($category, $level = 0) {
          if ($category->parent_id>0) {
              if ($category->parent) {
                      $level++;
                      return $this->getDepth($category->parent, $level);
                  }
              }
             return $level;
          }
      

      也许它会对某人有所帮助! 干杯!

      【讨论】:

      • 还有$loop->depth()使用递归foreach
      【解决方案5】:

      你可以这样解决这个问题:

      class Category extends Model
      {
          public function categories()
          {
             return $this->hasMany(Category::class);
          }
      
          public function childrenCategories()
          {
             return $this->hasMany(Category::class)->with('categories');
          }
      
      }
      

      并获得这样的孩子的类别:

      Category::whereNull('category_id')
          ->with('childrenCategories')
          ->get();
      

      注意:只需将 parent_id 列重命名为 category_id

      【讨论】:

        【解决方案6】:

        这也有效:

        查看:

            $traverse = function ($categories) use (&$traverse) {
                foreach ($categories as $category) $traverse($cat->Children);
            };
            $traverse(array ($category));
        

        型号:

        public function Children()
        {
            return $this->hasMany($this, 'parent');
        }
        
        public function Parent()
        {
            return $this->hasOne($this,'id','parent');
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-01-11
          • 2022-01-16
          相关资源
          最近更新 更多