In this tutorial, we will build a comment system with replies using Laravel 11. This system allows users to add comments and replies to comments, creating a threaded discussion. Let’s walk through the steps to create this feature in a simple and understandable way.
Step 1: Set Up Laravel Project
First, you need to set up a new Laravel project. If you haven’t installed Laravel yet, you can do so by following the official documentation.
composer create-project --prefer-dist laravel/laravel comment-system
cd comment-system
Step 2: Set Up Database
Configure your database in the .env
file. Update the following lines with your database details:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=your_database_name
DB_USERNAME=your_database_user
DB_PASSWORD=your_database_password
Run the migration to create the necessary tables:
php artisan migrate
Step 3: Create Models and Migrations
We need two models: Post
and Comment
. The Post
model represents a blog post, and the Comment
model represents comments and replies.
Create the Post
model and migration:
php artisan make:model Post -m
Create the Comment
model and migration:
php artisan make:model Comment -m
Update the posts
migration file to create the posts
table:
// database/migrations/xxxx_xx_xx_create_posts_table.php
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('content');
$table->timestamps();
});
}
Update the comments
migration file to create the comments
table:
// database/migrations/xxxx_xx_xx_create_comments_table.php
public function up()
{
Schema::create('comments', function (Blueprint $table) {
$table->id();
$table->foreignId('post_id')->constrained()->onDelete('cascade');
$table->foreignId('parent_id')->nullable()->constrained('comments')->onDelete('cascade');
$table->text('content');
$table->timestamps();
});
}
Run the migrations:
php artisan migrate
Step 4: Define Relationships in Models
Update the Post
model to define the relationship with comments:
// app/Models/Post.php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
use HasFactory;
protected $fillable = ['title', 'content'];
public function comments()
{
return $this->hasMany(Comment::class)->whereNull('parent_id');
}
}
Update the Comment
model to define the relationship with posts and replies:
// app/Models/Comment.php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
use HasFactory;
protected $fillable = ['post_id', 'parent_id', 'content'];
public function post()
{
return $this->belongsTo(Post::class);
}
public function replies()
{
return $this->hasMany(Comment::class, 'parent_id');
}
}
Step 5: Create Controllers
We need a controller for handling posts and comments. Create a PostController
:
php artisan make:controller PostController
Update the PostController
to handle displaying posts and adding comments:
// app/Http/Controllers/PostController.php
namespace App\Http\Controllers;
use App\Models\Post;
use App\Models\Comment;
use Illuminate\Http\Request;
class PostController extends Controller
{
public function index()
{
$posts = Post::all();
return view('posts.index', compact('posts'));
}
public function show(Post $post)
{
return view('posts.show', compact('post'));
}
public function storeComment(Request $request, Post $post)
{
$request->validate(['content' => 'required']);
$post->comments()->create([
'content' => $request->content,
'parent_id' => $request->parent_id
]);
return back();
}
}
Step 6: Define Routes
Define routes for displaying posts and adding comments in web.php
:
// routes/web.php
use App\Http\Controllers\PostController;
Route::get('/', [PostController::class, 'index']);
Route::get('/posts/{post}', [PostController::class, 'show']);
Route::post('/posts/{post}/comments', [PostController::class, 'storeComment'])->name('comments.store');
Step 7: Create Views
Create a view for displaying posts and comments. First, create a layout file:
<!-- resources/views/layouts/app.blade.php -->
<!DOCTYPE html>
<html>
<head>
<title>Comment System</title>
<link rel="stylesheet" href="{{ asset('css/app.css') }}">
</head>
<body>
<div class="container">
@yield('content')
</div>
</body>
</html>
Create a view for listing posts:
<!-- resources/views/posts/index.blade.php -->
@extends('layouts.app')
@section('content')
<h1>Posts</h1>
@foreach($posts as $post)
<div>
<h2><a href="{{ url('/posts', $post->id) }}">{{ $post->title }}</a></h2>
<p>{{ $post->content }}</p>
</div>
@endforeach
@endsection
Create a view for displaying a single post and its comments:
<!-- resources/views/posts/show.blade.php -->
@extends('layouts.app')
@section('content')
<h1>{{ $post->title }}</h1>
<p>{{ $post->content }}</p>
<h2>Comments</h2>
<form action="{{ route('comments.store', $post) }}" method="POST">
@csrf
<textarea name="content" rows="3" required></textarea>
<input type="hidden" name="parent_id" value="">
<button type="submit">Add Comment</button>
</form>
@foreach($post->comments as $comment)
<div style="margin-left: 20px;">
<p>{{ $comment->content }}</p>
<form action="{{ route('comments.store', $post) }}" method="POST" style="margin-left: 20px;">
@csrf
<textarea name="content" rows="2" required></textarea>
<input type="hidden" name="parent_id" value="{{ $comment->id }}">
<button type="submit">Reply</button>
</form>
@include('posts.partials.comments', ['comments' => $comment->replies])
</div>
@endforeach
@endsection
Create a partial view for displaying nested comments:
<!-- resources/views/posts/partials/comments.blade.php -->
@foreach($comments as $comment)
<div style="margin-left: 20px;">
<p>{{ $comment->content }}</p>
<form action="{{ route('comments.store', $post) }}" method="POST" style="margin-left: 20px;">
@csrf
<textarea name="content" rows="2" required></textarea>
<input type="hidden" name="parent_id" value="{{ $comment->id }}">
<button type="submit">Reply</button>
</form>
@include('posts.partials.comments', ['comments' => $comment->replies])
</div>
@endforeach
Step 8: Run the Application
You can now run your application and test the comment system:
php artisan serve
Visit http://localhost:8000
in your browser, and you should see the list of posts. Click on a post to view its details and add comments and replies.
Conclusion
In this tutorial, we have created a simple comment system with replies in Laravel 11. We covered setting up the project, defining models and relationships, creating controllers, defining routes, and building views. This should give you a good starting point to build more complex comment systems with nested replies.
- Check our tools small Tools
- Check our tools website Word count