Building a Self-Referencing Model in Laravel: A Step-by-Step Guide

Building a Self-Referencing Model in Laravel: A Step-by-Step Guide

1. Introduction

Self-referencing models, also known as recursive relationships, are a powerful tool in Laravel's Eloquent ORM (Object-Relational Mapping) system. They allow a model to have a relationship with itself, which can be useful for data structures that have a hierarchical or recursive nature. For example, a category model may have a parent-child relationship with itself, whereas a parent category can have multiple child categories.

Self-referencing models can also be used for data structures such as comments, where a comment can have a parent comment and multiple child comments. They can also be used for data structures such as tree structures where each node can have multiple children nodes.

Using self-referencing models can make it easier to manage and structure complex data, and can also help to improve the performance and efficiency of your application. In this guide, we will walk you through the process of building a self-referencing model in Laravel, from setting up the database to using the model in your application.

This is how the relationship is but with the same model.

Source: GeeksForGeeks

2. Setting Up the Database

One of the most important things to consider when setting up the database is the use of a foreign key. In a self-referencing model, the foreign key column is used to reference the primary key of the same table.

First, we will create the users table by running the following command in the terminal:

php artisan make:migration add_parent_id_users_table

This command will create a new migration file in the "database/migrations" directory. In this file, we will define the columns for the users table, including the parent_id column as a foreign key.

Add the below code in up and down methods.

public function up()
{
    Schema::table('users', function (Blueprint $table) {
        $table->unsignedBigInteger('parent_id')->nullable();
        $table->foreign('parent_id')
              ->references('id')->on('users')
              ->cascadeOnUpdate()->cascadeOnDelete();
    });
}

public function down()
{
    Schema::table('users', function (Blueprint $table) {
       $table->dropForeign(['parent_id']);
       $table->dropColumn(['parent_id']);
    });
}

Once we have defined the columns for the users table, we can run the following command to create the table in the database:

php artisan migrate

3. Adding Relations in Model


    /**
     * This will give model's Parent 
     * @return BelongsTo
     */
    public function parent(): BelongsTo
    {
        return $this->belongsTo(self::class, 'parent_id');
    }

    /**
     * This will give model's Parent, Parent's parent, and so on until root.  
     * @return BelongsTo
     */
    public function parentRecursive(): BelongsTo
    {
        return $this->parent()->with('parentRecursive');
    }

    /**
     * Get current model's all recursive parents in a collection in flat structure.
     */
    public function parentRecursiveFlatten()
    {
        $result = collect();
        $item = $this->parentRecursive;
        if ($item instanceof User) {
            $result->push($item);
            $result = $result->merge($item->parentRecursiveFlatten());
        }
        return $result;
    }

    /**
     * This will give model's Children
     * @return HasMany
     */
    public function children(): HasMany
    {
        return $this->hasMany(self::class, 'parent_id');
    }

    /**
     * This will give model's Children, Children's Children and so on until last node. 
     * @return HasMany
     */
    public function childrenRecursive(): HasMany
    {
        return $this->children()->with('childrenRecursive');
    }

As you can see from the above code that there are 5 methods I have added to the user model. Consider the below diagram which shows the self-referencing column.

Table UML diagram, which shows parent_id is foreign key from same table.

4. Using the Self-Referencing Model in the Application

If you have looked at the image in the introduction section. Node 1 is the root of all the nodes and nodes 8, 9, 10, 11, 13, and 14 are the last level nodes.

Now let's say you want to get the child, grandchild, parent or grandparent or root node from any node. We will consider all the scenarios and we will see the examples below on how to use all methods from our user model.

Get parent node

$user = User::find(8); 
$parent = $user->parent; // 4

Get all the parent nodes (Tree structure)

$user = User::find(8); 
$parent = $user->parentRecursive; // 4,2,1 as a tree structure

This will return all parents as a tree. To get all the parent lists in a flat array use the below code.

Get all the parent nodes (Flat collection)

$user = User::find(8); 
$parent = $user->parentRecursiveFlatten; // [4,2,1]

This will return all parents as a flat collection

Get the grandparent

$user = User::find(8); 
$parent = $user->parent()->parent; // 2

Get Children

$user = User::find(2); 
$parent = $user->children; // [4,5]

Get all Children

$user = User::find(2); 
$parent = $user->childrenRecursive; // 4, 5, 8, 9, 10, 11

Get GrandChildren

$user = User::find(2); 
$parent = $user->children()->children; // [4,5]

This is a gist with all the relations, check it out: https://gist.github.com/technoknol/68bd2bcaca8efa7c8e7c9ed533414ce3

5. Conclusion

Building a self-referencing model in Laravel is a straightforward process once you understand the underlying principles and methodologies. By following the step-by-step guide outlined in this article, you can create a self-referencing model that can handle complex data relationships with ease. Whether you are an experienced Laravel developer or just starting, this guide will provide you with a solid foundation to build your next self-referencing model. With the right approach and a little bit of practice, you'll be able to create complex and sophisticated data relationships that help you make the most of your data.

If you're stuck and need professional help, reach out to us at https://ghanshyamdigital.com/ our Laravel professionals will help you get things done.

Did you find this article valuable?

Support Ghanshyam Digital by becoming a sponsor. Any amount is appreciated!