Johan Swart
Johan Swart

Reputation: 43

Laravel 5 eloquent recursive programming

I have then next 2 tables

/* systems */
id    sys_name
 1    Debtors
 2    Creditors
 3    Cashbook

/* menus */
id    system_id    parent_id   menu_desc
1         1            0       Maintenance
2         1            1       Maintain Debtors
3         1            2       Debtor Addresses
4         1            1       Maintain Clerks
5         3            0       Bank Reconciliation

I have 2 Eloquent models

/* System */
public function menus(){ 
   return this->hasMany(Menu::class,'system_id','id')->where('menus.parent_id','=',0);
}
public function submenus(){ 
   return this->hasMany(Menu::class,'system_id','id')->where('menus.parent_id','=','menus.id');
}

/* Menu */
public function system(){
   return $this->belongsTo(System::class,'system_id','id');
}
public function parent(){
   return $this->hasOne(Menu::class,'id','parent_id');
}
public function children(){ 
   return $this->hasMany(Menu::class,'parent_id','id');
}

I want to achieve the following in blade.php:

@foreach($systems as $system)
   ....... 
   @foreach($menus as $menu)
      .......
      @foreach($submenus as $submenu)
          ........
       @endforeach
    @endforeach
 @endforeach

with the following output: (I am using bootstrap for indentation)

Debtors
   Maintenance
      Maintain Debtors
         Debtor Addresses
      Maintain Clerks
Creditors
Cashbook
   Bank Reconciliation

MenuController

$systems = System::with('menus','submenus')->get();

but it doesn't work. There are no submenu records. I think the problem is 'menus.id' in function submenus() but dont know how to solve it.

Please help as I have battled more than 3 days to build a menu treeview.

Thanking you in advance

Upvotes: 2

Views: 924

Answers (2)

irfani arief
irfani arief

Reputation: 91

You need to put the submenus() function on the menu model file, since your tree structure is system menu submenu

or you can just change the with syntax to

$systems = System::with('menus','menus.children')->get();

and change the submenu foreach with $menu.children

@foreach($menu->children as $submenu)

Upvotes: 0

Joshua David
Joshua David

Reputation: 291

The easiest way to do what you want is to use a nested relation.

Instead of trying to build a ->submenus() relation, instead just use the already-existing ->children() relation on your Menu class:

Route::get('systems', function() {
    $systems = System::with('menus.children')->get();
    return view('systems')->with('systems', $systems);
});

Then your systems.blade.php template can just be something like

<pre>
Systems
@foreach($systems as $system)
    {{$system->sys_name}} Menus
    @foreach($system->menus as $menu)
        {{$menu->menu_desc}} Submenus
        @foreach($menu->children as $submenu)
            {{$submenu->menu_desc}}
        @endforeach
    @endforeach
@endforeach
</pre>

As an additional advantage to that method, you can get all menus with subsubsubmenus with System::with('menus.children.children.children')->get(), and so on.

Upvotes: 2

Related Questions