Laravel + Eloquent: Storing comments and nested comments

Updated: January 25, 2024 By: Guest Contributor Post a comment

Introduction

When building a web application that requires user interaction, such as a blog or a forum, incorporating a commenting system is a common need. With Laravel, an MVC framework and Eloquent ORM, creating and managing comments, including nested comments, becomes a streamlined process. This guide will help you understand how to implement a comment system in Laravel using Eloquent ORM, including handling nested or reply-to comments in a hierarchical manner.

Before we begin, you should have Laravel installed on your machine along with Composer, a PHP package manager. Ensure that you have a database configured as Laravel requires a database to store comment data.

Setting up the Comment Model

First, we’ll start by creating a Model and a migration for comments:

php artisan make:model Comment -m

In the generated migration file, define the structure of the comments table:

Schema::create('comments', function (Blueprint $table) {
    $table->id();
    $table->text('body');
    $table->unsignedBigInteger('user_id');
    $table->unsignedBigInteger('parent_id')->nullable();
    $table->foreign('user_id')->references('id')->on('users');
    $table->timestamps();
});

The parent_id column is crucial as it keeps track of comment replies. The foreign method ensures that the user_id column relates to a valid user in the users table.

Defining the Relationships

In the Comment model, define the relationships:

class Comment extends Model
{
    // Comment belongs to a user
    public function user()
    {
        return $this->belongsTo(User::class);
    }

    // Reply relationship (a comment can have many replies)
    public function replies()
    {
        return $this->hasMany(Comment::class, 'parent_id');
    }
}

Here we’ve defined a belongsTo relationship to the User and a hasMany relationship for replies.

Creating Nested Comments

To handle nested comments, consider the following controller method:

public function postComment(Request $request, $id)
{
    $comment = new Comment();
    $comment->body = $request->body;
    $comment->user_id = auth()->id();
    $comment->parent_id = $request->parent_id; // null for top-level comments
    $post = Post::find($id);
    $post->comments()->save($comment);

    return back();
}

This method attaches a comment to a post, with parent_id used to determine if it’s a top-level comment or a nested reply.

Displaying Comments with Nesting

To display comments and their nested replies, use a recursive approach, such as a Blade partial:

<div class="comments">
    <ul>
        @foreach($comments as $comment)
            <li>
                <p>{{ $comment->user->name }}: {{ $comment->body }}</p>
                @include('comments.reply', ['comments' => $comment->replies])
            </li>
        @endforeach
    </ul>
</div>

The comments.reply partial will be similar but designed to iterate through the replies of a particular comment.

Efficient Querying with Eager Loading

Instead of querying the database multiple times, use eager loading with the with method to reduce the number of queries when fetching comments:

$comments = Comment::whereNull('parent_id')
    ->with('user', 'replies.user')
    ->get();

This fetches all top-level comments along with their user data and nested replies efficiently.

Conclusion

By following this guide, you’ve learned how to create a commenting system with nested comments in Laravel using Eloquent’s ORM features. With the techniques outlined, you can now build a robust commenting system that can scale as needed and enhance user interaction within your Laravel application.