【问题标题】:Recursively display dropdown in laravel在 laravel 中递归显示下拉菜单
【发布时间】:2015-09-08 04:37:01
【问题描述】:

假设我有一个名为categories 的表,例如:

id   parent_id  title
1        0      food
2        1      drinks
3        2      juice
4        0      furniture
5        3       tables

现在我想在 laravel 上创建下拉菜单,以便它递归地显示父类别下的子类别,并根据深度进行适当的缩进或 - 标记。例如:

<select>
 <option value="1">food</option>
 <option value="2">-drinks</option>
 <option value="3">--juice</option>
 <option value="4">furniture</option>
 <option value="5">-tables</option>
</select>

以上是静态的,但我想像上面一样从 laravel 中的 categories 表中递归地生成任何深度的子类别的下拉结构。

【问题讨论】:

    标签: php laravel laravel-5


    【解决方案1】:

    首先,您可以在控制器上定义一个 getCategories 方法。一种递归方法。理想情况下,您应该实现以下内容:

    ...
    
    // utility method to build the categories tree
    private function getCategories($parentId = 0)
    {
        $categories = [];
    
        foreach(Category::where('parent_id', 0)->get() as $category)
        {
            $categories = [
                'item' => $category,
                'children' => $this->getCategories($category->id)
            ];
        }
    
        return $categories;
    }
    
    ...
    

    之后,您应该将最终的数组/集合(或您选择的任何内容)传递给视图。

    return view('my_view', ['categories' => $this->getCategories()])
    

    最后,您可以使用类似于this one 的解决方案。

    【讨论】:

    • 我可以使用分页吗?
    【解决方案2】:

    不是最优雅的,但可以完成工作:

    <?php
    
    $data = [
        ['id' => 1, 'parent_id' => 0, 'title' => 'food'],
        ['id' => 2, 'parent_id' => 1, 'title' => 'drinks'],
        ['id' => 3, 'parent_id' => 2, 'title' => 'juice'],
        ['id' => 4, 'parent_id' => 0, 'title' => 'furniture'],
        ['id' => 5, 'parent_id' => 4, 'title' => 'tables']
    ];
    
    function recursiveElements($data) {
        $elements = [];
        $tree = [];
        foreach ($data as &$element) {
            $element['children'] = [];
            $id = $element['id'];
            $parent_id = $element['parent_id'];
            $elements[$id] =& $element;
            if (isset($elements[$parent_id])) { $elements[$parent_id]['children'][] =& $element; }
            else { $tree[] =& $element; }
        }
        return $tree;
    }
    
    function flattenDown($data, $index=0) {
        $elements = [];
        foreach($data as $element) {
            $elements[] = str_repeat('-', $index) . $element['title'];
            if(!empty($element['children'])) $elements = array_merge($elements, flattenDown($element['children'], $index+1));
        }
        return $elements;
    }
    
    $recursiveArray = recursiveElements($data);
    
    $flatten = flattenDown($recursiveArray);
    
    print_r($flatten);
    
    /*
    Outputs:
    Array
    (
        [0] => food
        [1] => -drinks
        [2] => --juice
        [3] => furniture
        [4] => -tables
    )
     */
    

    【讨论】:

      【解决方案3】:

      在您的 Category Eloquent 模型上运行 get 方法或使用查询构建器来获取所有类别。

      然后编写一个函数并根据需要多次递归调用它。 filter 方法对处理您的类别集合非常有帮助

      这样的事情应该可以工作:

      function getCategories($categories, &$result, $parent_id = 0, $depth = 0)
      {
          //filter only categories under current "parent"
          $cats = $categories->filter(function ($item) use ($parent_id) {
              return $item->parent_id == $parent_id;
          });
      
          //loop through them
          foreach ($cats as $cat)
          {
              //add category. Don't forget the dashes in front. Use ID as index
              $result[$cat->id] = str_repeat('-', $depth) . $cat->title;
              //go deeper - let's look for "children" of current category
              getCategories($categories, $result, $cat->id, $depth + 1);
          }
      }
      
      //get categories data. In this case it's eloquent.
      $categories = Category::get();
      //if you don't have the eloquent model you can use DB query builder:
      //$categories = DB::table('categories')->select('id', 'parent_id', 'title')->get();
      //prepare an empty array for $id => $formattedVal storing
      $result = [];
      //start by root categories
      getCategories($categories, $result);
      

      自己没有测试过,但是思路应该够清楚了。好消息是您只执行一个查询。坏事是你一次将整个表加载到内存中。

      如果您的表有更多列而您不需要此算法,则应在查询中仅指定所需的列。

      【讨论】:

      • 我最喜欢这个解决方案。非常感谢你。这里唯一缺少的是函数末尾的 return 语句,即return $result;
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-04-25
      • 2012-05-27
      • 1970-01-01
      • 1970-01-01
      • 2018-08-16
      • 1970-01-01
      • 2013-08-12
      相关资源
      最近更新 更多