2013-05-04 130 views
6

模型Laravel菜單自遞歸

class Menu extends Eloquent { 

     public static $table = 'menus'; 

     public function parent_menu() 
     { 
      return $this->belongs_to('Menu', 'parent_id'); 
     } 

    } 

我怎麼得到它的控制器:

$menus = Menu::with('parent_menu')->get(); 

我怎麼呈現在視圖:

foreach($menus as $m) 
{ 
    echo $m->parent_menu->title; 
} 

看起來像有是關係是在一個表內的問題,我得到一個錯誤

`trying to get property of non object` 

有沒有解決方案呢?

+0

看起來像我需要使用數據透視錶針對這種情況 – Hello 2013-05-04 22:07:39

+0

你確定你是試圖讓該菜單項有一個父? 「試圖獲得非對象的屬性」表明沒有'parent_menu'可用。 – 2013-05-05 17:12:33

+0

在這裏發佈此爲來自搜索的人http://heera.it/laravel-model-relationship – Jarry 2014-09-11 18:50:07

回答

0

這可能有一些幫助。繼承人我如何與產品類別/子類別

做到了

型號:

<?php 

class Category extends Eloquent { 

    protected $table = 'product_category'; 

    public function subcat() 
    { 
     return $this->hasMany('Category', 'node_id')->orderBy('position'); 
    } 

查詢(您可以使用預先加載時使用條件)

$categories = Category::with(['subcat' => function($query){ 
    $query->with(['subcat' => function($query){ 
     $query->orderBy('name'); 
    }]) 
}])->where('node_id', 0)->orderBy('position')->get(['id', 'name']); 

foreach ($categories as $level1) 
{ 
    echo $level1->name; 

    foreach ($level1->subcat as $level2) 
    { 
     echo $level2->name; 

     foreach ($level2->subcat as $level3) 
     { 
       echo $level3->name; 
     } 
    } 
} 
+0

但這是有限的水平,我想使它無限深 – Hello 2013-05-04 23:39:50

4

我實現了一個辦法讓無盡在Laravel 4中的菜單深度。這不完全是你問的,但技術應該很容易適應。

對於初學者我的菜單只是一個數組(現在)被分配到主視圖,看起來像這樣。

$menu = array(
    array(
    'name' => 'item1', 
    'url' => '/' 
    ), 
    array(
    'name' => 'item2', 
    'url' => '/', 
    'items' => array(
     array(
      'name' => 'subitem1', 
      'url' => '/' 
     ), 
     array(
      'name' => 'subitem2', 
      'url' => '/' 
     ) 
    ) 
    ) 
); 

您也可以通過使用模型來輕鬆實現此結構。你需要功能child_items或者其他的東西,因爲我們會從上往下渲染菜單,而不是從下往上渲染。

現在在我的主基片模板我這樣做:

<ul> 
    @foreach ($menu as $item) 
     @include('layouts._menuItem', array('item' => $mainNavItem)) 
    @endforeach 
</ul> 

然後在layouts._menuItem模板我這樣做:

<?php 
$items = array_key_exists('items', $item) ? $item['items'] : false; 
$name = array_key_exists('name', $item) ? $item['name'] : ''; 
$url = array_key_exists('url', $item) ? url($item['url']) : '#'; 
$active = array_key_exists('url', $item) ? Request::is($item['url'].'/*') : false; 
?> 

<li class="@if ($active) active @endif"> 
     <a href="{{ $url }}">{{ $name }}</a> 
     @if ($items) 
      <ul> 
      @foreach ($items as $item) 
       @include('layouts._menuItem', array('item' => $item)) 
      @endforeach 
      </ul> 
     @endif 
</li> 

正如你可以看到這個模板遞歸調用自己,但一個不同的$item變量。這意味着您的菜單結構可以儘可能深入。 (php塊只是在那裏準備一些變量,所以我可以保持實際的模板代碼清潔和可讀,從技術上說它不是必需的)。

我在上面的代碼片斷中刪除了Twitter Bootstrap代碼,以使事情變得簡單(實際上我有模板/數組中的標題,下拉切換,圖標,分隔符等),所以代碼未經測試。儘管如此,完整版仍然適合我,所以讓我知道我是否在某個地方犯了錯誤。

希望這可以幫助你(或其他人,因爲這是一個相當古老的問題)的道路上。讓我知道你是否需要更多的指針/幫助,或者如果你想要我的完整代碼。

快樂編碼!

2

我相信以下是在laravel中進行遞歸的正確方法。

假設我們有一個孩子的關係,你可以添加到您的模型類:

public function getDescendants ($parent= false) { 
    $parent = $parent ?: $this; 
    $children = $parent->children()->get(); 

    foreach ($children as $child) { 
     $child->setRelation(
      'children', 
      getDescendants($child) 
     ); 
    } 

    return $children; 
} 

以上將得到所有的孩子遞歸記錄,你可以像這樣訪問他們:

$d = Category::find(1)->getDescendants(); 

foreach ($d as $child_level_1) { 
    foreach ($child_level_1->children as $child_level_2) { 
     foreach ($child_level_2->children as $child_level_3) { 
      // ...... this can go on for infinite levels 
     } 
    } 
} 

雖然未經測試,但以下可能有助於將所有遞歸關係平鋪爲一個模型集合(check the documentation on adding new methods to collections):

// Add this to your model 
public function newCollection (array $models = array()) { 
    return new CustomCollection($models); 
} 


// Create a new file that extends the orginal collection 
// and add the flattenRelation method 
class CustomCollection extends Illuminate\Database\Eloquent\Collection { 
    // Flatten recursive model relations 
    public static function flattenRelation ($relation) { 
     $collection = $this; 
     // Loop through the collection models 
     foreach ($collection as $model) { 

      // If the relation exists 
      if (isset($model->relations[$relation])) { 
       // Get it 
       $sub_collection = $model->relations[$relation]; 

       // And merge it's items with the original collection 
       $collection = $collection->merge(
        $sub_collection->flatten($relation) 
       ); 

       // Them remove it from the relations 
       unset($model->relations[$relation]); 
      } 

     } 

     // Return the flattened collection 
     return $collection; 
    } 
} 

這樣,你可以做到以下幾點:

// This will get the descenands and flatten them recursively 
$d = Category::find(1)->getDescendants()->flattenRelation('children'); 

// This will give you a flat collection of all the descendants 
foreach ($d as $model) { 

} 
1

我laravel無限子菜單菜單(從數據庫菜單項)

public function CreateMenu($parid, $menu, $level) { 

    $output = array();  
    $action= Route::current()->getUri(); 
    $uri_segments = explode('/', $action); 
    $count=count($uri_segments); 
    foreach($menu as $item => $data) { 

      if ($data->parent_id == $parid) { 
       $uri=''; 
       $output[ $data->id ] = $data; 
       for($i=0; $i<=$level; $i++) { 
        if($i < $count) { 
         $uri.="/".Request::segment($i+1); 
        } 
        if($uri == $data->link) { 
         $output[ $data->id ]->activeClass = 'active'; 
         $output[ $data->id ]->inClass = 'in'; 
        } 
        else { 
         $output[ $data->id ]->activeClass = ''; 
         $output[ $data->id ]->inClass = ''; 
        } 
        $output[ $data->id ]->level = $level+2; 
       } 
       $output[ $data->id ]->submenu = self::CreateMenu($data->id, $menu, $level+1); 
      } 

    } 
    return $output; 

} 

在BaseController或者你想,把

$navitems=DB::table('navigations')->get(); 
$menu=BaseController::CreateMenu(0,$navitems,0); 
return View::share($menu); 

之後,我把菜單html的宏.php

HTML::macro('MakeNavigation', function($data) { 

foreach ($data as $key => $value) { 
    if($value->submenu) { 
     echo '<li class="'.$value->activeClass.'"> 
     <a href="'.$value->link.'" class="'.$value->activeClass.'">"' 
      .$value->name.' <span class="fa arrow"></span> 
     </a>'; 
     echo "<ul class='nav nav-".$value->level."-level ".$value->inClass." '>"; 
      HTML::MakeNavigation($value->submenu); 
     echo "</ul>"; 
    } 
    else { 
     echo '<li class="'.$value->activeClass.'"> 
     <a href="'.$value->link.'" class="'.$value->activeClass.'">' 
         .$value->name.' 
     </a>'; 
    } 
    echo "</li>"; 
}}); 

並在視圖(刀模板)只是調用

{{ HTML::MakeNavigation($menu) }}