【问题标题】:Laravel 4 - Eloquent. Infinite children into usable array?Laravel 4 - 雄辩。无限的孩子​​进入可用的数组?
【发布时间】:2018-03-23 23:08:12
【问题描述】:

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

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

示例日期:

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

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

有关 laravel 的文档很糟糕,甚至没有真正提到从哪里开始。几天来我一直在玩它,试图弄清楚该怎么做,但如果没有一个巨大的混乱块,每个循环相互之间有 10 次,我似乎一无所获。

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

<?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 循环,您就无法对子数据进行任何操作。

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

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

【问题讨论】:

  • 嵌套集实际上更简单。另外,已经有一些现有的包,比如Cartalyst's Nested SetsBaum
  • Jason,与公认的答案相比,嵌套集的优势是什么?我必须在两者之间做出决定。对于 Baum,似乎无论如何都无法检索那棵树,除非您也使用公认的答案。

标签: php parent-child laravel laravel-4 eloquent


【解决方案1】:

这比我平常早上的填字游戏有趣得多。 :)

这是一个 ItemsHelper 类,它可以满足您的需求,而且可以递归到您想要的任何地方。

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 视图。

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

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

虽然我的视图不使用 items 变量,但我将它传递到这里是因为您可能还想对它们做其他事情。

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

&lt;?= $itemsHelper-&gt;htmlList(); ?&gt;

输出如下:

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

注意:您的 SQL Fiddle 有 5(“Orange”)作为 Cucumber 和 Lettuce 的 parent_id,我必须将其更改为 6(“Veg”)。

【讨论】:

  • @MarkSmith - 很好的答案,谢谢!只是难以理解如何向数组添加附加值?甚至添加命名值?例如:{ id: '2', name: 'Parent 2', children: [ { id: '5', name: 'Sub 2a' }, { id: '6', name: 'Sub 2b' } ] }
  • 非常有帮助!谢谢!
  • 我也想知道如何添加附加值...@MarkSmith
  • 这是一个很好的解决方案,但只有一件事,那就是不好。问题是视图是在模型中生成的,而不是视图本身,如果你遵循 MVC 模式,除了视图文件之外,你不应该在任何地方有任何 HTML。还有另一种解决方案,递归调用刀片子模板,但仍然不是一个好的解决方案,尽管它遵循 MVC 模式
  • 甜蜜!有没有办法返回正在迭代的整个对象?而不仅仅是名字?
【解决方案2】:

我已经扩展了 Mark Smith 接受的答案,以允许生成的列表引用传递给类的附加数据。

该类的工作方式几乎相同,但我已将其打包,希望它可以轻松使用。

只需在控制器中引用帮助类:

use App\Helpers\CategoryHierarchy;

然后您可以手动实例化该类,或者使用 Laravel 5 的方法注入,事情会变得更好:

$products = $product->getAllProducts();
$hierarchy->setupItems($products);
return $hierarchy->render();

这可以输出以下内容:

<ul class='simple-list'>
   <li><input type="checkbox" name="hierarchy-checkboxes[]" value="1" >Home delivery</li>
      <ul>
        <li><input type="checkbox" name="hierarchy-checkboxes[]" value="2" >Italian</li>
          <ul>
            <li><input type="checkbox" name="hierarchy-checkboxes[]" value="3" >Pizza</li>
            <li><input type="checkbox" name="hierarchy-checkboxes[]" value="4" >Pasta</li>
          </ul>
        <li><input type="checkbox" name="hierarchy-checkboxes[]" value="5" >Burgers</li>
      </ul>
</ul>

有一个 repo 可用:https://github.com/amochohan/CategoryHierarchy 更详细地解释了。

【讨论】:

    【解决方案3】:

    我使用此功能使其工作。

     //Returns Root elements
     public function scopeRoot($query) {
            $all = $query->whereParent(0)->get();
            $collection = $all->filter(function($single) {
                if ($single->ModelFilter('GET')) {
                    return $single;
                }
            });
            return $collection;
        }
        //Recursive call
        public function traverse() {
            self::_traverse($this->Children, $array, $this);
            return $array;
        }
    
        //This function build a multidimensional array based on a collection of elements
        private static function _traverse($collection, &$array, $object) {
            $new_array = array();
            foreach ($collection as $element) {
                self::_traverse($element->Children, $new_array, $element);
            }
            $array[] = $object;
            if (count($new_array) > 0) {
                $array[] = $new_array;
            }
        }
    

    首先我得到一个根元素的集合,这些根元素是我传递给我想要列出树的视图的那些......

    那我就...

     <ul class="bg-info cat-list">
            @foreach($categories as $category)
            <?php
            $array = $category->traverse();
            list_view($array);
            ?>
            @endforeach
        </ul>
    

    使用此功能...

    //Prints a multidimensional array as a nested HTML list
    function list_view($element, $ul = true) {
        foreach ($element as $value) {
            if (!is_array($value)) {
                echo "<li>";
                echo $value->name;
            } else {
                echo ($ul) ? "<ul>" : "<ol>";
                list_view($valuce, $ul);
                echo "</li>";
                echo ($ul) ? "</ul>" : "</ol>";
            }
        }
    }
    

    希望对你有帮助

    【讨论】:

      猜你喜欢
      • 2019-06-24
      • 1970-01-01
      • 2013-09-09
      • 2015-06-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-15
      • 1970-01-01
      相关资源
      最近更新 更多