2013-05-04 135 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) }}