php – Larevel nested hasMany relationship for a dynamic menu-ThrowExceptions

Exception or error:

I’m trying to create a nestable dynamic menu with Laravel.
I have a hasMany relationship and I’m trying to get the children of the children of the parent.

Here’s what I mean:

class Menu extends Model
{
    protected $fillable = [
        'category_id', 'page_id', 'parent_id'
    ];

    public function childs() {
        return $this->hasMany('App\Menu','parent_id','id') ;
    }

    public function categories() {
        return $this->hasMany('App\Category','id','category_id') ;
    }

    public function pages() {
        return $this->hasMany('App\Page','id','page_id') ;
    }
}
>>> use App\Menu
>>> Menu::with('childs')->get();
=> Illuminate\Database\Eloquent\Collection {#3089
     all: [
       App\Menu {#3098
         id: 1,
         category_id: 2,
         page_id: 3,
         parent_id: null,
         created_at: "2020-03-17 10:12:46",
         updated_at: "2020-03-17 10:12:46",
         childs: Illuminate\Database\Eloquent\Collection {#3106
           all: [
             App\Menu {#3109
               id: 2,
               category_id: 2,
               page_id: 2,
               parent_id: 1,
               created_at: "2020-03-17 10:16:12",
               updated_at: "2020-03-17 10:16:12",
             },
           ],
         },
       },
       App\Menu {#3099
         id: 2,
         category_id: 2,
         page_id: 2,
         parent_id: 1,
         created_at: "2020-03-17 10:16:12",
         updated_at: "2020-03-17 10:16:12",
         childs: Illuminate\Database\Eloquent\Collection {#3097
           all: [
             App\Menu {#3111
               id: 4,
               category_id: 5,
               page_id: null,
               parent_id: 2,
               created_at: "2020-03-17 10:57:01",
               updated_at: "2020-03-17 10:57:01",
             },
           ],
         },
       },
       App\Menu {#3100
         id: 3,
         category_id: 1,
         page_id: 5,
         parent_id: null,
         created_at: "2020-03-17 10:53:58",
         updated_at: "2020-03-17 10:53:58",
         childs: Illuminate\Database\Eloquent\Collection {#3090
           all: [],
         },
       },
       App\Menu {#3101
         id: 4,
         category_id: 5,
         page_id: null,
         parent_id: 2,
         created_at: "2020-03-17 10:57:01",
         updated_at: "2020-03-17 10:57:01",
         childs: Illuminate\Database\Eloquent\Collection {#3091
           all: [],
         },
       },
     ],
   }

What the db looks like:
enter image description here

If you look at the output of Menu::with('childs')->get();, i’m only getting the first child, but not the child of the child etc..
Under menu id 1, there’s menu id 2, and under menu id 2 there should be menu id 4, but it’s not showing in the output.

I have tried to get it like this, but:

>>> $child = $menus->childs
=> Illuminate\Database\Eloquent\Collection {#3083
     all: [
       App\Menu {#3080
         id: 2,
         category_id: 2,
         page_id: 2,
         parent_id: 1,
         created_at: "2020-03-17 10:16:12",
         updated_at: "2020-03-17 10:16:12",
       },
     ],
   }
>>> $child->childs
Exception with message 'Property [childs] does not exist on this collection instance.'
>>> foreach($child as $ch){$ch->childs;}

Basically, i’m just trying to get a JSON like structure of my dynamic menu. Is there any way i can do this in eloquent ?

How to solve:

you need to create some recursive function.

in Controller:

$structure == collect();
$master_menu_collection = Menu::where('parent_id', null)->get();
foreach ($master_menu_collection as $menu) {
    $structure->push($menu->getAll());
}

dd($structure);

Recursive function

public function getAll()
{
    if ($this->childs->count() > 0) {
        $this->childs()->each->getAll();
    }
    return $this;
}

Let me know, if it works.

Leave a Reply

Your email address will not be published. Required fields are marked *