Do you want to have parent child level relationship into your laravel project? then you are at right place this tutorial will give you everything you need to build parent child Recursive Relationship in Laravel using Eloquent HasMany Relationship method.
Recommended – How to Implement Laravel Eloquent One-to-Many Relationship
Let’s get started
Table of Contents
Create Database Table Structure
Create new database model and a migration file which we use to define our categories table
php artisan make:model Categories -m
Add following columns for categories table
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateCategoriesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('categories', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('title');
$table->unsignedBigInteger('category_id')->nullable();
$table->timestamps();
$table->foreign('category_id')
->references('id')
->on('categories')
->onDelete('set null');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('categories');
}
}
Migrate the database
php artisan migrate
laravel6 git:(master) ✗ php artisan migrate
Migrating: 2019_09_09_164026_create_categories_table
Migrated: 2019_09_09_164026_create_categories_table (0.07 seconds)
Just so you understand the table schema if you see here we have single table where are going to store parent as well as child categories.
We have used category_id column as parent category indicator for corresponding row.
If the category_id column is empty which means given category is a root category it does not have any parent items.
So all sub categories will have category id in it and finally if the given category is deleted then the sub category will become root category.
Add few records according to your need in categories table, for this demo I am going to add dummy items like showing below
Define Eloquent model Relationship
This is important part of this tutorial and this is the main reason of writing this tutorial because it is the actual solution to have Laravel HasMany Recursive Relationship in your project.
Open Categories model from app folder and define following methods:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Categories extends Model
{
// this relationship will only return one level of child items
public function categories()
{
return $this->hasMany(Categories::class, 'category_id');
}
// This is method where we implement recursive relationship
public function childCategories()
{
return $this->hasMany(Categories::class, 'category_id')->with('categories');
}
}
If we try to get records like this
Categories::with('categories')->get()
It will returns us only one level of child items and here is the magic if you call
Categories::with('childCategories')->get();
It is going to give us all items with recursive relationship.
Next’s lets see how we can show this relationship using Laravel Blade View
Create new Controller and Define Route
We will this control to fetch categories from the database using our Categories eloquent model and pass it to the laravel blade file
php artisan make:controller CategoriesController
Define getCategories
method in CategoriesController
, this is the method where we are going to fetch all the categories with parent child relationship.
/app/Http/Controllers/CategoriesController.php
<?php
namespace App\Http\Controllers;
use App\Categories;
class CategoriesController extends Controller
{
public function getCategories()
{
$categories = Categories::whereNull('category_id')
->with('childCategories')
->orderby('title', 'asc')
->get();
return view('categories', compact('categories'));
}
}
Define route to get categories under web.php
file:
Route::get('/get-categories', 'CategoriesController@getCategories');
Create Parent View and Child View:
This is also and important part while your displaying recursive categories list, we are going to need two views here first is the one which display the first level parent categories and second view is the one which is going to list out all the child level categories.
Create new file called categories.blade.php
under views folder
/resources/views/categories.blade.php
<ul>
@if(count($categories) > 0)
@foreach ($categories as $category)
<li>{{ $category->title }}</li>
<ul>
@if(count($category->childCategories))
@foreach ($category->childCategories as $subCategories)
@include('sub_categories', ['sub_categories' => $subCategories])
@endforeach
@endif
</ul>
@endforeach
@endif
</ul>
As you can see here in the above example I have added foreach
loop to loop over the $categories
array and then next for sub level I have included sub_categories
view using @include
Go ahead and create sub view called sub_categories.blade.php
/resources/views/sub_categories.blade.php
<li>{{ $sub_categories->title }}</li>
@if ($sub_categories->categories)
<ul>
@if(count($sub_categories->categories) > 0)
@foreach ($sub_categories->categories as $subCategories)
@include('sub_categories', ['sub_categories' => $subCategories])
@endforeach
@endif
</ul>
@endif
So here is the another magic happening first we are looping from the $sub_categories->categories
array and next we have included same view itself so it will keep on going to iterate over until the last child item form the array.
So this how we can implement Eloquent HasMany Recursive Relationship with Subitems in Laravel Framework.
If you access /get-categories route you should see following parent child level output:
If you get any question specify to this tutorial let me know using comment box below.
You have a typo:
return $this->hasMany(Categories::class, ‘category_id’)->with(‘categories’);
Instead of ‘categories’ you need to pass ‘childCategories’ to make recursive call
thanks
Hello, have you checked with query optimization? Because if you have more than thousands of records then you can see thousands of queries executed. check with laravel debug bar you will get idea about my issue