2013-05-14 23 views
10

Tôi có bảng danh mục. Mỗi thể loại có thể có một phụ huynh tùy chọn (mặc định là 0 nếu không có cha mẹ).Laravel 4 - Eloquent. Trẻ em vô hạn vào mảng có thể sử dụng?

Điều tôi muốn làm là tạo một cây danh sách html đơn giản với các cấp độ của các danh mục.

ngày Ví dụ:

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

Lưu ý rằng điều này cần phải làm việc cho khoảng 10 'mức'. Tôi muốn nó là vô hạn nhưng tôi thực sự không muốn đi xuống con đường của việc sử dụng một mô hình tập lồng nhau vì nó sẽ gây ra sự chậm trễ rất lớn về dự án này.

Tài liệu về điều này cho ấu trùng là khủng khiếp, không có tham chiếu thực sự về nơi bắt đầu. Tôi đã chơi với nó trong nhiều ngày cố gắng để làm việc ra phải làm gì và dường như nhận được hư không mà không có một khối lộn xộn rất lớn cho mỗi vòng trong mỗi 10 lần khác.

Tôi đã có cây của tôi về dữ liệu bằng cách sử dụng sau đây trong mô hình của tôi:

<?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(); 
    } 
} 

này được tất cả phụ huynh và trẻ em lên đến một mức độ 10 này hoạt động tốt, nhưng bạn không thể thực sự thì đừng bất kỳ thứ gì có dữ liệu con mà không có 10 vòng lặp foreach theo cách thủ công.

Tôi đang làm gì sai ở đây? Chắc chắn đây không phải là điều này khó khăn/kém thực hiện? Tất cả những gì tôi muốn làm là lấy một danh sách html đơn giản với các mục trong cấu trúc cây.

tôi đã đặt cùng một ví dụ SQLFiddle nhanh chóng của các dữ liệu giả sử dụng trên: http://sqlfiddle.com/#!2/e6d18/1

+0

Bộ lồng nhau thực sự đơn giản hơn. Ngoài ra, có một số gói hiện có, như [Bộ lồng tổ hợp của Cartalyst] (http://docs.cartalyst.com/nested-sets-2) hoặc [Baum] (https://github.com/etrepat/baum). –

+0

Jason, lợi thế của bộ lồng nhau so với câu trả lời được chấp nhận là gì? Tôi phải quyết định giữa hai người. Và với Baum, có vẻ như không có cách nào để lấy cây đó, trừ khi bạn sử dụng câu trả lời được chấp nhận là tốt. – kJamesy

Trả lời

38

Đây là niềm vui nhiều hơn bình thường câu đố ô chữ buổi sáng của tôi. :)

Đây là lớp ItemsHelper sẽ làm những gì bạn đang tìm kiếm, và tốt hơn là sẽ recurse như xa xuống như bạn muốn.

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

tôi chỉ sử dụng một cài đặt mới của Laravel 4 và hello.php xem cơ bản.

Đây là tuyến đường của tôi trong app/routes.php:

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

Mặc dù quan điểm của tôi không sử dụng các mặt hàng biến, tôi đi qua nó ở đây vì có thể bạn sẽ muốn làm điều gì đó khác với họ quá.

Và cuối cùng, app/views/hello.php của tôi chỉ có một dòng:

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

Kết quả trông như thế này:

  • Foods
    • Fruit
      • của Apple
      • Banana
      • Orange
    • Veg
      • Dưa chuột
      • Rau diếp
  • Drinks
    • cồn
      • Bia
      • Vodka
  • Misc
    • gia Objects
      • bếp
        • Điện
          • Cooking
            • Stove
            • Toaster
            • lò vi sóng

Lưu ý: SQL Fiddle của bạn có 5 ("Cam") làm parent_id cho Cucumber và Xà lách, tôi phải thay đổi thành 6 ("Veg").

+1

Tuyệt vời! Rất cảm ơn vì điều này :) – Sk446

+2

Bạn đang khá hoan nghênh! Vui vì tôi có thể giúp đỡ. –

+1

@MarkSmith - câu trả lời tuyệt vời cảm ơn bạn! Chỉ cần đấu tranh để hiểu làm thế nào bạn sẽ thêm các giá trị bổ sung cho mảng? Hoặc thậm chí thêm các giá trị được đặt tên? Ví dụ: '{ id: '2', tên: 'Chánh 2', trẻ em: [ { id: '5', tên: 'Sub 2a' }, { id: '6', tên: 'Tiểu 2b' } ] } ' – Fraccus

1

Tôi sử dụng chức năng này để hoạt động.

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

Đầu tiên tôi nhận được một bộ sưu tập của các yếu tố gốc đó là những người mà tôi vượt qua những quan điểm của tôi, nơi tôi muốn liệt kê các cây ...

Sau đó, tôi làm ...

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

Sử dụng chức năng này ...

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

Output

Hy vọng điều này sẽ giúp

1

Tôi đã mở rộng câu trả lời được chấp nhận bởi Mark Smith để cho phép danh sách được tạo để tham chiếu dữ liệu bổ sung được chuyển vào lớp học.

Lớp học hoạt động theo cách tương tự, nhưng tôi đã đóng gói nó lên để hy vọng nó có thể được sử dụng dễ dàng.

Chỉ cần tham khảo các lớp helper trong điều khiển của bạn:

use App\Helpers\CategoryHierarchy; 

Bạn có thể sau đó, hoặc nhanh chóng lớp bằng tay, hoặc sử dụng Laravel 5 của điều phương pháp tiêm nhận được thậm chí tốt hơn:

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

này có thể xuất như sau:

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

Có sẵn repo: https://github.com/drawmyattention/CategoryHierarchy giải thích chi tiết hơn.

Các vấn đề liên quan