Laravel 4 - 雄辩.无限的孩子​​变成可用的数组?

2021-12-26 00:00:00 parent-child php laravel laravel-4 eloquent

我有一个类别表.每个类别可以有一个可选的父级(如果没有父级,则默认为 0).

I've got a categories table. Each category can have an optional parent (Defaults to 0 if no parent).

我想要做的是用类别的级别构建一个简单的 html 列表树.

What I want to do is build a simple html list tree with the levels of the categories.

示例日期:

Foods
-- Fruit
---- Apple
---- Banana
---- Orange
-- Veg
---- Cucumber
---- Lettuce
Drinks
-- Alcoholic
---- Beer
---- Vodka
Misc
-- Household Objects
---- Kitchen
------ Electrical
-------- Cooking
---------- Stove
---------- Toaster
---------- Microwave

请注意,这需要在大约 10 个级别"内工作.我希望它是无限的,但我真的不想走使用嵌套集模型的路线,因为它会导致这个项目的巨大延迟.

Note that this needs to work for around 10 'levels'. I'd love it to be infinite but I really dont want to be going down the route of using a nested set model as it'll cause huge delays on this project.

关于 laravel 的文档很糟糕,甚至没有真正提到从哪里开始.我已经玩了好几天了,试图弄清楚该做什么,但如果没有一个巨大的 for each 循环块 10 次,我似乎一无所获.

The docs on this for laravel are terrible, with no real reference as to where to even start. I've been playing with it for days trying to work out what to do and seem to be getting nowhere without a huge messy block of for each loops within each other 10 times.

我在我的模型中使用了以下数据树:

I've got my tree of data using the following in my model:

<?php
class Item extends Eloquent {
    public function parent()
    {
        return $this->hasOne('Item', 'id', 'parent_id');
    }

    public function children()
    {
        return $this->hasMany('Item', 'parent_id', 'id');
    }

    public function tree()
    {
        return static::with(implode('.', array_fill(0,10, 'children')))->where('parent_id', '=', '0')->get();
    }
}

这会将所有父级和子级提升到 10 级.这很好用,但如果不手动在彼此内部使用 10 个 foreach 循环,您就无法真正对子数据执行任何操作.

This gets all the parent and children up to a level of 10. This works fine, but you cant really then do anything with the child data without manually having 10 foreach loops within each other.

我在这里做错了什么?当然,这不应该如此艰难/执行不力吗?我想要做的就是获得一个简单的 html 列表,其中包含树结构中的项目.

What am I doing wrong here? Surely this shouldn't be this hard/poorly executed? All I want do do is get a simple html list with the items in a tree structure.

我已经整理了一个上面使用的虚拟数据的快速 SQLFiddle 示例:http://sqlfiddle.com/#!2/e6d18/1

I've put together a quick SQLFiddle example of the dummy data used above: http://sqlfiddle.com/#!2/e6d18/1

推荐答案

这比我平时早上的填字游戏有趣多了.:)

This was much more fun than my usual morning crossword puzzle. :)

这是一个 ItemsHelper 类,它将执行您正在寻找的操作,并且更好地递归到您想要的范围.

Here is an ItemsHelper class that will do what you are looking for, and better yet will recurse as far down as you want.

app/models/ItemsHelper.php:

<?php

  class ItemsHelper {

    private $items;

    public function __construct($items) {
      $this->items = $items;
    }

    public function htmlList() {
      return $this->htmlFromArray($this->itemArray());
    }

    private function itemArray() {
      $result = array();
      foreach($this->items as $item) {
        if ($item->parent_id == 0) {
          $result[$item->name] = $this->itemWithChildren($item);
        }
      }
      return $result;
    }

    private function childrenOf($item) {
      $result = array();
      foreach($this->items as $i) {
        if ($i->parent_id == $item->id) {
          $result[] = $i;
        }
      }
      return $result;
    }

    private function itemWithChildren($item) {
      $result = array();
      $children = $this->childrenOf($item);
      foreach ($children as $child) {
        $result[$child->name] = $this->itemWithChildren($child);
      }
      return $result;
    }

    private function htmlFromArray($array) {
      $html = '';
      foreach($array as $k=>$v) {
        $html .= "<ul>";
        $html .= "<li>".$k."</li>";
        if(count($v) > 0) {
          $html .= $this->htmlFromArray($v);
        }
        $html .= "</ul>";
      }
      return $html;
    }
  }

我刚刚使用了新安装的 Laravel 4 和基本的 hello.php 视图.

I just used a new installation of Laravel 4 and the basic hello.php view.

这是我在 app/routes.php 中的路线:

Here is my route in app/routes.php:

Route::get('/', function()
{
  $items = Item::all();
  $itemsHelper = new ItemsHelper($items);
  return View::make('hello',compact('items','itemsHelper'));
});

虽然我的视图没有使用 items 变量,但我在这里传递它是因为你可能也想用它们做其他事情.

Although my view doesn't use the items variable, I'm passing it here because you probably will want to do something else with them too.

最后,我的 app/views/hello.php 只有一行:

And finally, my app/views/hello.php just has one line:

htmlList();?>

输出如下:

  • 食物
    • 水果
      • 苹果
        • 香蕉
        • 橙色
        • 蔬菜
          • 黄瓜
          • 生菜
          • 饮料
            • 酒精
              • 啤酒
              • 伏特加
              • 杂项
                • 家居用品
                  • 厨房
                    • 电器
                      • 烹饪
                        • 炉灶
                        • 烤面包机
                        • 微波炉

                        注意:您的 SQL Fiddle 有 5(Orange")作为 Cucumber 和 Lettuce 的 parent_id,我不得不将其更改为 6(Veg").

                        Note: your SQL Fiddle had 5 ("Orange") as the parent_id for Cucumber and Lettuce, I had to change it to 6 ("Veg").

相关文章