Today I am going to discuss the nested comment and reply system in Laravel 8. Hope you will enjoy 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 create a comment and reply system in the Laravel 8 application. We will see it from scratch.
Many developers look for a good package for the comment and reply system, but now we are going to create it without any packages. I will create a very simple comment system where you can add a post and then you can leave a comment and can make a reply to any specific post.
I will make a polymorphic relationship to create this comment and reply system. Having completed this tutorial you won't need to use any packages like the 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 create a post table and a comment table. So let's start our brand new tutorial nested comment system in laravel 8.
Step 1 : Install Laravel 8
Now download laravel 8 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 a 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', 'PostController@create')->name('post.create');
Route::post('post', 'PostController@store')->name('post.store');
Route::get('/posts', 'PostController@index')->name('posts');
Route::get('/article/{post:slug}', 'PostController@show')->name('post.show');
Route::post('/comment/store', 'CommentController@store')->name('comment.add');
Route::post('/reply/store', 'CommentController@replyStore')->name('reply.add');
Step 7: Create Blade Files
In the last step. In this step, we have to create blade files. So we have to create a 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
I have an error here: View [post.partials.replies] not found. Any clue? Is there any github repo link? Thanks