11

カテゴリテーブルがあります。各カテゴリは、オプションの親を持つことができます (親がない場合、デフォルトは 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 回ループする for each の巨大な乱雑なブロックなしではどこにも行けないようです。

モデルで次を使用して、データのツリーを取得しました。

<?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

4

3 に答える 3

39

これは、いつもの朝のクロスワード パズルよりもずっと楽しかったです。:)

これは、探していることを実行する 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行は1行だけです:

<?= $itemsHelper->htmlList(); ?>

出力は次のようになります。

  • 食品
    • フルーツ
      • アップル
      • バナナ
      • オレンジ
    • ベジ
      • キュウリ
      • レタス
  • 飲み物
    • アルコール依存症
      • ビール
      • ウォッカ
  • その他
    • 家庭用品
      • キッチン
        • 電気
          • 料理
            • ストーブ
            • トースター
            • 電子レンジ

注: SQL Fiddle には、Cucumber と Lettuce のparent_id として 5 ("Orange") がありました。6 ("Veg") に変更する必要がありました。

于 2013-05-14T16:04:07.780 に答える
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>

リポジトリが利用可能です: https://github.com/amochohan/CategoryHierarchyで、より詳細に説明されています。

于 2015-01-19T13:39:54.823 に答える
1

この関数を使用して機能させます。

 //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>";
        }
    }
}

出力

それが役に立てば幸い

于 2014-07-24T18:38:18.993 に答える