Create Multilevel Nested Comment System in Laravel 7.x Example

100374 views 2 years ago Laravel

Hey Artisan

Hope you are doing well in Laravel. Today i am coming with a pristinely incipient tutorial. Today i am going to discuss about nested comment and reply system in Laravel 7. Hope you will relish it.

A Comment system is a key feature of any blog or any website. So in this example tutorial i am going to show you how we can engender comment and reply system in Laravel 7 application. We will visually perceive it from scratch.

Many developer probes for a good package for comment and reply system, but now we are going to engender it without any packages. I will engender very simple comment system where you can integrate post and then you can leave a comment and can make a replication to any concrete post.

I will make polymorphic relationship to engender this comment and reply system. Having consummated this tutorial you won't require to utilize any packages like Facebook comments plugin, or discuss comment plugin to your website.

You can make your own comment system to your website by following this tutorial. I will engender a post table and a comment table. So let's commence our pristinely incipient tutorial nested comment system in laravel 7.

One more thing, you have to make it professional. So now let's start comment and reply system in laravel.

Step 1 : Install Laravel 7

Now download laravel 7 to start our project. So run below command to download it.

composer create-project --prefer-dist laravel/laravel blog

Step 2: Create Post and Comment Model

We need Post and Comment model to create comment and reply system. So let's create it. Run below command

php artisan make:model Post -m

Define the schema in the post migration file.

public function up()
{
    Schema::create('posts', function (Blueprint $table) {
        $table->id();
        $table->string('title');
        $table->string('slug');
        $table->timestamps();
    });
}

Also, we need to create Comment model and migration file, so create using the following command.

php artisan make:model Comment -m

Having done it, Now i will do the polymorphic relationship between those models. So i need to define the schema below way

public function up()
{
    Schema::create('comments', function (Blueprint $table) {
       $table->increments('id');
       $table->integer('user_id')->unsigned();
       $table->integer('parent_id')->unsigned();
       $table->text('comment');
       $table->integer('commentable_id')->unsigned();
       $table->string('commentable_type');
       $table->timestamps();
    });
}

Now run this below command to migrate our post and comment table.

php artisan migrate

Step 3: Create Auth

As only authenticated user can leave a comment. So we need to create auth in our application. So let's make it.You need to follow some few steps to complete auth in your laravel 7 application. First you need to install laravel/ui package.

composer require laravel/ui

Now you can use following commands for creating auth:

php artisan ui bootstrap --auth

Step 4: Create Relationship

Now, we need to define the Polymorphic relationships and other relationship which will be needed in this tutorial. So do it.

app/Post.php

namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
    protected $guarded = [];
    public function user()
    {
        return $this->belongsTo(User::class);
    }
    public function comments()
    {
        return $this->morphMany(Comment::class, 'commentable')->whereNull('parent_id');
    }
}

app/Comment.php

namespace App;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{   
    protected $guarded = [];
    public function user()
    {
        return $this->belongsTo(User::class);
    }
    public function replies()
    {
        return $this->hasMany(Comment::class, 'parent_id');
    }
}

app/User.php

namespace App;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
    use Notifiable;
    protected $fillable = [
        'name', 'email', 'password',
    ];
    public function posts() {
        return $this->hasMany(Post::class);
    }
}

Step 5: Create Controller

In this step, now we should create new controller as PostController and CommentController. So run bellow command and create new controller

php artisan make:controller PostController

and now paste this below code to your post controller.

app/Http/Controllers/PostController.php

namespace App\Http\Controllers;
use App\Post;
use App\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
class PostController extends Controller
{
    public function __construct()
    {
       $this->middleware('auth');
    }
    public function index()
    {
       $posts = Post::take(5)->get();
       return view('post.index', compact('posts'));
    }
    public function create()
    {
        return view('post.create');
    }
    public function store(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'title' => 'required|min:3',
        ]);
        if ($validator->fails()) {
            return redirect('post')
                        ->withErrors($validator)
                        ->withInput();
        }
        Post::create([
            'title' => $request->title,
            'slug' => \Str::slug($request->title)
        ]);
        return redirect()->back();
    }
    public function show(Post $post) {
        return view('post.single',compact('post'));
    }
}

And now we have to create our comment controller. So now create it.

php artisan make:controller CommentController

and now paste this below code to your comments controller.

app/Http/Controllers/CommentController.php

namespace App\Http\Controllers;
use App\Post;
use App\Comment;
use Illuminate\Http\Request;
class CommentController extends Controller
{
    public function store(Request $request)
    {
        $comment = new Comment;
        $comment->comment = $request->comment;
        $comment->user()->associate($request->user());
        $post = Post::find($request->post_id);
        $post->comments()->save($comment);
        return back();
    }
    public function replyStore(Request $request)
    {
        $reply = new Comment();
        $reply->comment = $request->get('comment');
        $reply->user()->associate($request->user());
        $reply->parent_id = $request->get('comment_id');
        $post = Post::find($request->get('post_id'));
        $post->comments()->save($reply);
        return back();
    }
}

Step 6: Create Routes

Now we have to create our routes to view our comment and reply file. Paste this below code to your web.php.

routes/web.php

Route::get('post', '[email protected]')->name('post.create');
Route::post('post', '[email protected]')->name('post.store');
Route::get('/posts', '[email protected]')->name('posts');
Route::get('/article/{post:slug}', '[email protected]')->name('post.show');
Route::post('/comment/store', '[email protected]')->name('comment.add');
Route::post('/reply/store', '[email protected]')->name('reply.add');

Step 7: Create Blade Files

In last step. In this step we have to create blade files. So we have to create post folder and in the post folder we will create our view file.

resources/views/post/index.blade.php

@extends('layouts.app')
@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <table class="table table-striped">
                <thead>
                    <th>No</th>
                    <th>Title</th>
                    <th>Action</th>
                </thead>
                <tbody>
                @foreach($posts as $post)
                <tr>
                    <td>{{ $post->id }}</td>
                    <td>{{ $post->title }}</td>
                    <td>
                        <a href="{{ route('post.show',$post->slug) }}" class="btn btn-sm btn-outline-danger py-0" style="font-size: 0.8em;">Read Post</a>
                    </td>
                </tr>
                @endforeach
                </tbody>
            </table>
        </div>
    </div>
</div>
@endsection 

resources/views/post/create.blade.php

@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">Create Post</div>
                <div class="card-body">
                    @error('title')
                        <div class="alert alert-danger">{{ $message }}</div>
                    @enderror
                    <form method="post" action="{{ route('post.store') }}">
                        <div class="form-group">
                            @csrf
                            <label class="label">Post Title: </label>
                            <input type="text" name="title" class="form-control" required/>
                        </div>
                        <div class="form-group">
                            <input type="submit" class="btn btn-success" value="Create post"/>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection 

resources/views/post/single.blade.php

@extends('layouts.app')
<style>
    .display-comment .display-comment {
        margin-left: 40px
    }
</style>
@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-body">
                    <p>{{ $post->title }}</p>
                </div>
               <div class="card-body">
                <h5>Display Comments</h5>
                @include('post.partials.replies', ['comments' => $post->comments, 'post_id' => $post->id])
                <hr />
               </div>
               <div class="card-body">
                <h5>Leave a comment</h5>
                <form method="post" action="{{ route('comment.add') }}">
                    @csrf
                    <div class="form-group">
                        <input type="text" name="comment" class="form-control" />
                        <input type="hidden" name="post_id" value="{{ $post->id }}" />
                    </div>
                    <div class="form-group">
                        <input type="submit" class="btn btn-sm btn-outline-danger py-0" style="font-size: 0.8em;" value="Add Comment" />
                    </div>
                </form>
               </div>
            </div>
        </div>
    </div>
</div>
@endsection 

resources/views/post/partials/replys.blade.php

@foreach($comments as $comment)
<div class="display-comment">
    <strong>{{ $comment->user->name }}</strong>
    <p>{{ $comment->comment }}</p>
    <a href="" id="reply"></a>
    <form method="post" action="{{ route('reply.add') }}">
        @csrf
        <div class="form-group">
            <input type="text" name="comment" class="form-control" />
            <input type="hidden" name="post_id" value="{{ $post_id }}" />
            <input type="hidden" name="comment_id" value="{{ $comment->id }}" />
        </div>
        <div class="form-group">
            <input type="submit" class="btn btn-sm btn-outline-danger py-0" style="font-size: 0.8em;" value="Reply" />
        </div>
    </form>
    @include('post.partials.replies', ['comments' => $comment->replies])
</div>
@endforeach 

Now we are ready to run check our nested comment system application with laravel 7. Now you can open bellow URL on your browser:

http://localhost:8000/post

i hope you like this article.

Author : Harsukh Makwana
Harsukh Makwana

Hi, My name is Harsukh Makwana. i have been work with many programming language like php, python, javascript, node, react, anguler, etc.. since last 5 year. if you have any issue or want me hire then contact me on [email protected]