Laravel Eloquent HasMany Recursive Relationship with Subitems

Today I’m going to show how to view items and deep level sub-items. Let’s get started:

Table of Contents

  1. Database Migration
  2. Eloquent Model and Relationships
  3. Modify Controller and Define Route
  4. Create Views

Database Migration

Create a model, migrations and controller using this command:

php artisan make:model Item -mc

Open the newly created migration file from database/migrations folder and update up() method:

public function up()
{
    Schema::create('items', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->unsignedBigInteger('parent_id')->nullable();
        $table->foreign('parent_id')->references('id')->on('items');
        $table->timestamps();
    });
}

Now migrate the database:

php artisan migrate

Eloquent Model and Relationships

We’re going to add two relations in app/Item.php model. One for displaying level one items and another one for showing recursive items:

class Item extends Model
{
    // return one level of child items
    public function items()
    {
        return $this->hasMany(Item::class, 'parent_id');
    }

    // recursive relationship
    public function childItems()
    {
        return $this->hasMany(Item::class, 'parent_id')->with('items');
    }
}

Modify Controller and Define Route

Open ItemController from app\Http\Controllers and add the index() method:

<?php

namespace App\Http\Controllers;

use App\Item;
use Illuminate\Http\Request;

class ItemController extends Controller
{
    public function index() {
        $items = Item::whereNull('parent_id')
            ->with('childItems')
            ->get();

        return view('items', compact('items'));
    }
}

Now define a route in routes/web.php for the index() method:

Route::get('items', 'ItemController@index');

Create Views

Go to resources/views folder and create 2 files named items.blade.php and sub_items.blade.php. Then paste these codes:

items.blade.php
<ul>
    @if(count($items) > 0)
        @foreach ($items as $item)
            <li>{{ $item->name }}</li>
            <ul>
                @if(count($item->childItems))
                    @foreach ($item->childItems as $childItems)
                        @include('sub_items', ['sub_items' => $childItems])
                    @endforeach
                @endif
            </ul>
        @endforeach
    @endif
</ul>
sub_items.blade.php
<li>{{ $sub_items->name }}</li>
@if ($sub_items->items)
    <ul>
        @if(count($sub_items->items) > 0)
            @foreach ($sub_items->items as $childItems)
                @include('sub_items', ['sub_items' => $childItems])
            @endforeach
        @endif
    </ul>
@endif

Now insert some data into items tables and run the project. Then visit http://localhost:8000/items route to see the output. Here’s my one:

That’s it. Thanks for reading.