I was working on application where I had to create hierarchical relationship for a Model entity and also figure out a way to display it in HTML.

I decided to write an article on this as I came across similar questions over the internet and the process which I have gone through might help someone looking for similar solution.

Alright so first things first, If you already don't know let's first get to know how to structure a hierarchical relationship in Laravel through an example and then in second part we will go into the details of how we can display it.

Create Hierarchical Relationship in Laravel

For this article we will consider an simplest example of multi-level dataset i.e. category and subcategory.

Here is how the category-subcategory relationship looks like

A category can have multiple subcategory, a subcategory can also have multiple subcategory and so on...

Let's consider you have a Category model in your application and you are looking to have a relationship with the self table so that you can store subcategories as well.

Setup Model, Migration and Relationship

Let's set up a Category model along with the migration file

php artisan make:model Category -m

This artisan command will generate a Category model along with the migration file.

Let's now go ahead and modify the migration file to add the required columns.

public function up(){
        Schema::create('categories', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('name');
            $table->unsignedInteger('parent_id')->nullable();
            $table->timestamps();
        });
}

We have added two new columns

  1. name : This will be used to store the name of the category
  2. parent_id : This will be used to store the id of the associated parent category for a subcategory

Next, let's go ahead and create a relationship for our category subcategory data.

Open Category.php model file located in App directory and add following relationship method

 public function subcategory(){
        return $this->hasMany('App\Category', 'parent_id');
    }

Read the relationship as : A Category and have many Category (Subcategory) and is associated with parent_id foreign key.

This is a relationship with self-table.

This is all you need to setup the hierarchical relationship.

Following is how you can extract the data

Get All Category with no Parent Category

Category::where('parent_id',NULL)->get();

Get All sub-categories for a Category

$category->subcategory

Simple, Isn't it !

Display Hierarchical Relationship in Laravel

Alright, next move on to the next part where we have to show all the category and the subcategory in our view html page.

This part is a  little tricky for the following reasons.

  1. We need a recursion loop since we are not sure of the depth till category have further subcategories.
  2. HTML Representation needs to club subcategories, under the category of which they are part of.

There are different ways to show hierarchal / multi-level data.

  1. Simple HTML Unordered List
  2. Tree View
  3. Hierarchical Data in Tabular Format.
  4. Menu with Drop-downs.

In this tutorial we will go over unordered list and tabular format.

First things first, Let's create a controller method where we get all the topmost parent categories and pass them on to the view.


public function index(){  
        $parentCategories = Category::where('parent_id',NULL)->get();
        return view('categories', compact('parentCategories'));
    }

This code get's all the categories with no parent categories and sends them to the view file.

Now let's see how we can represent the categories in our view file.

Simple HTML Unordered List

The best way to test your hierarchical relationship view is to throw the output in HTML unordered list.

Here is how the main blade file categories.blade.php looks.


@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">Categories</div>
                <div class="card-body">
                    @foreach($parentCategories as $category)
                        <ul>
                            <li>{{$category->name}}</li>
                            @if(count($category->subcategory))
                                 @include('subCategoryList',['subcategories' => $category->subcategory])
                            @endif 
                        </ul>
                    @endforeach
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

We loop through the list of parent categories and show them in HTML list, If a category consist of subcategories we show pass it to another view subCategoryList

This is how subCategoryList.blade.php file looks


@foreach($subcategories as $subcategory)
        <ul>
            <li>{{$subcategory->name}}</li> 
	    @if(count($subcategory->subcategory))
            @include('subCategoryList',['subcategories' => $subcategory->subcategory])
        @endif
        </ul> 
@endforeach

We have made use of recursion to call this view file again and again until the parent does have any further child data.

That's it. Here is how the output looks. I have used faker library to generate some fake parent child data.

hierarchical view laravel

Hierarchical Table Data

You can also choose to show the hierarchical data in the tabular format. To demonstrate the example I am using a jquery plugin Treetable-Bootstrap. This plugin will make the task of collapsing the subcategory into a category easier.

You need to include the required bootstrap and treetable js file.

The controller method looks like this


public function index(){  
   $parentCategories = Category::where('parent_id',NULL)->get();
    return view('categories-table', compact('parentCategories'));
}

The categories-table.blade.php view file looks like this

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">Dashboard</div>

                <div class="card-body">
                <table id="tree-table" class="table table-hover table-bordered">
                    <tbody>
                    <th>Categories </th>
                            @foreach($parentCategories as $category)
                                <tr data-id="{{$category->id}}" data-parent="0" data-level="1">
                                    <td data-column="name">{{$category->name}}</td>
                                </tr>
                                @if(count($category->subcategory))
                                    @include('subCategoryView',['subcategories' => $category->subcategory, 'dataParent' => $category->id , 'dataLevel' => 1])
                                @endif      
				            @endforeach
                        </tbody>
                    
                    </table>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

We loop through the list of parent categories and show them in table row, If a category consist of subcategories we show pass it to another view subCategoryView

@foreach($subcategories as $subcategory)
        <tr data-id="{{$subcategory->id}}" data-parent="{{$dataParent}}" data-level = "{{$dataLevel + 1}}">
            <td data-column="name">{{$subcategory->name}}</td>
        </tr>
	    @if(count($subcategory->subcategory))
            @include('subCategoryView',['subcategories' => $subcategory->subcategory, 'dataParent' => $subcategory->id, 'dataLevel' => $dataLevel ])
        @endif
@endforeach

Hierarchical data in tabular format looks like the screenshot below

laravel multilevel data in table format

 

Similarly you can use recursion to display the Laravel hierarchical in Tree View or Nav Bar.

Comments