Installation
composer require xlabs/commentbundle
Add to config/app.php under providers:
Xlabs\CommentBundle\CommentBundle::class,
Publish the bundle’s assets and config:
php artisan vendor:publish --provider="Xlabs\CommentBundle\CommentBundle" --tag=config
php artisan vendor:publish --provider="Xlabs\CommentBundle\CommentBundle" --tag=assets
Database Migration Run the bundle’s migrations:
php artisan migrate
The bundle creates tables for comments, comment_threads, and comment_votes (if enabled).
Basic Usage
Attach comments to any model via a hasMany relationship:
// In your model (e.g., Post.php)
public function comments()
{
return $this->hasMany(\Xlabs\CommentBundle\Entity\Comment::class);
}
Create a comment:
$post = Post::find(1);
$comment = $post->comments()->create([
'body' => 'This is a test comment',
'user_id' => auth()->id(),
]);
Frontend Integration
Include the bundle’s JS/CSS in your layout (published to public/vendor/commentbundle/):
<link rel="stylesheet" href="{{ asset('vendor/commentbundle/css/comment.css') }}">
<script src="{{ asset('vendor/commentbundle/js/comment.js') }}"></script>
Use the provided Blade directives (if available) or manually render threads:
@foreach($post->comments as $comment)
<div class="comment">
<p>{{ $comment->body }}</p>
<small>By {{ $comment->user->name }} on {{ $comment->created_at->diffForHumans() }}</small>
</div>
@endforeach
Threaded Comments
The bundle supports nested replies via comment_threads. To fetch a comment with its replies:
$comment = Comment::with('replies')->find($id);
Blade Rendering:
@include('commentbundle::partials.comment_thread', ['comment' => $comment])
(Assumes the bundle provides a partials directory; verify via vendor/xlabs/commentbundle/resources/views.)
User Association
Comments are tied to users via user_id. Ensure your User model has a comments() relationship:
public function comments()
{
return $this->hasMany(\Xlabs\CommentBundle\Entity\Comment::class);
}
Guest Comments: Override the Comment model to allow anonymous comments (set user_id to null and track via IP/token).
Voting System (Optional)
If enabled, votes are stored in comment_votes. Add a votes() relationship to Comment:
public function votes()
{
return $this->hasMany(\Xlabs\CommentBundle\Entity\CommentVote::class);
}
Vote Logic:
$comment->votes()->create(['user_id' => auth()->id(), 'value' => 1]); // Upvote
Moderation
Use the is_approved flag on Comment:
$comment = Comment::find($id);
$comment->is_approved = true;
$comment->save();
Filtering Approved Comments:
$post->comments()->where('is_approved', true)->get();
CommentCreated, CommentUpdated, or CommentDeleted events (if the bundle emits them). Extend the Comment model to fire custom events:
protected static function boot()
{
parent::boot();
static::created(function ($comment) {
event(new \App\Events\CommentPosted($comment));
});
}
CommentResource (if provided) or create your own:
Route::apiResource('comments', \App\Http\Controllers\CommentController::class);
Controller Example:
public function store(Request $request, Post $post)
{
$comment = $post->comments()->create($request->validate([
'body' => 'required',
'user_id' => 'required|exists:users,id',
]));
return response()->json($comment, 201);
}
$comments = Cache::remember("post.$post->id.comments", now()->addHours(1), function () use ($post) {
return $post->comments()->with('replies')->get();
});
Missing Relationships
comments() relationship isn’t defined in your model.// In Post.php
public function comments() { return $this->hasMany(Comment::class); }
// In Comment.php (if not auto-generated)
public function post() { return $this->belongsTo(Post::class); }
Permission Bypass
$request->validate([
'user_id' => 'required_if:authenticated,1|exists:users,id',
]);
Thread Depth Limits
$comments = Comment::where('parent_id', null)
->with(['replies' => function ($query) {
$query->whereNull('parent_id')->orWhere('depth', '<', 3);
}])->get();
Asset Paths
public folder isn’t linked.config/commentbundle.php and ensure:
php artisan storage:link
Database Locking
DB::transaction(function () use ($post, $request) {
$post->comments()->create($request->all());
});
DB::enableQueryLog();
$comments = $post->comments()->get();
dd(DB::getQueryLog());
Comment::created(function ($comment) {
\Log::info('Comment created', ['id' => $comment->id]);
});
config/commentbundle.php:
'default_commentable_model' => \App\Models\Post::class,
'enable_voting' => false,
Custom Commentable Models
Extend the bundle to support comments on non-standard models (e.g., Video, Article). Override the Comment model’s commentable() relationship:
public function commentable()
{
return $this->morphTo();
}
Then define polymorphic relationships in your models:
// In Post.php
public function comments()
{
return $this->morphMany(Comment::class, 'commentable');
}
Custom Validation
Add rules to the Comment model’s $fillable or use form requests:
public function rules()
{
return [
'body' => 'required|min:3|max:2000',
'user_id' => 'required|exists:users,id',
];
}
Custom Views Override the bundle’s views by publishing and modifying them:
php artisan vendor:publish --tag=commentbundle-views
Then edit files in resources/views/vendor/commentbundle/.
API Extensions Add custom endpoints for comment actions (e.g., bulk moderation):
Route::post('/comments/{comment}/approve', [CommentController::class, 'approve']);
Controller:
public function approve(Comment $comment)
{
$comment->update(['is_approved' => true]);
return response()->json(['status' => 'approved']);
}
How can I help you explore Laravel packages today?