newway-solutions / laravel-comments
Add comments to your Laravel application
Requires
- php: ^8.1
- illuminate/support: ^10.0|^11.0|^12.0
Requires (Dev)
- orchestra/testbench: ^3.6|^5.0|^6.0|^7.0|^8.0
- phpunit/phpunit: ^9.5.8|^10.0.7
This package is auto-updated.
Last update: 2025-09-07 12:34:16 UTC
README
A Laravel package that provides a simple and flexible commenting system for your Laravel application. Add comments to any Eloquent model with support for nested replies, comment approval, and event-driven notifications.
Features
- ๐ฌ Add comments to any Eloquent model
- ๐ Nested comments and replies support
- โ Comment approval system
- ๐ฏ Polymorphic relationships
- ๐ก Event-driven architecture
- ๐ Flexible user authentication
- ๐งช Comprehensive test coverage
- ๐ฆ Easy installation and configuration
Requirements
- PHP 8.1 or higher
- Laravel 10.0, 11.0, or 12.0
Installation
You can install the package via composer:
composer require newway-solutions/laravel-comments
Publish and Run Migrations
Publish the migration and run it:
php artisan vendor:publish --provider="NewWaySo\Comments\CommentsServiceProvider" --tag="migrations" php artisan migrate
Publish Configuration (Optional)
You can publish the config file with:
php artisan vendor:publish --provider="NewWaySo\Comments\CommentsServiceProvider" --tag="config"
This will publish a config file to config/comments.php
where you can customize the package behavior.
Configuration
Basic Configuration
The configuration file allows you to customize several aspects:
<?php return [ /* * The comment class that should be used to store and retrieve * the comments. */ 'comment_class' => \NewWaySo\Comments\Comment::class, /* * The user model that should be used when associating comments with * commentators. If null, the default user provider from your * Laravel authentication configuration will be used. */ 'user_model' => null, /** * Determines if replies will be deleted when comments are deleted */ 'delete_replies_along_comments' => false, ];
Usage
Preparing Your Models
Making Models Commentable
To allow a model to have comments, use the HasComments
trait:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; use NewWaySo\Comments\Traits\HasComments; class Post extends Model { use HasComments; // Your model code here... }
Making Users Able to Comment
For users to be able to comment, implement the Commentator
contract and use the CanComment
trait:
<?php namespace App\Models; use Illuminate\Foundation\Auth\User as Authenticatable; use NewWaySo\Comments\Contracts\Commentator; use NewWaySo\Comments\Traits\CanComment; class User extends Authenticatable implements Commentator { use CanComment; /** * Check if a comment for a specific model needs to be approved. */ public function needsCommentApproval($model): bool { // Return false if the user's comments should be auto-approved // Return true if the user's comments need manual approval return false; // Auto-approve comments from this user } }
Basic Usage
Adding Comments
// Add a comment as the currently authenticated user $post = Post::find(1); $comment = $post->comment('This is a great post!'); // Add a comment as a specific user $user = User::find(1); $comment = $post->commentAsUser($user, 'This is a great post!'); // Add a comment without a user (anonymous comment) $comment = $post->commentAsUser(null, 'Anonymous comment');
Retrieving Comments
$post = Post::find(1); // Get all comments $comments = $post->comments; // Get only approved comments $approvedComments = $post->comments()->approved()->get(); // Get comments with their commentators (users) $commentsWithUsers = $post->comments()->with('commentator')->get();
Working with Nested Replies
$post = Post::find(1); $comment = $post->comment('This is the main comment'); // Reply to a comment $reply = $post->replyToComment($comment, 'This is a reply to the comment'); // Reply as a specific user $user = User::find(1); $reply = $post->replyToComment($comment, 'This is a reply', $user); // Get replies for a comment $replies = $comment->replies; // Get parent comment of a reply $parentComment = $reply->parent;
Comment Management
Approving and Disapproving Comments
$comment = Comment::find(1); // Approve a comment $comment->approve(); // Disapprove a comment $comment->disapprove(); // Check if comment is approved if ($comment->is_approved) { // Comment is approved }
Deleting Comments
$comment = Comment::find(1); // Delete a comment $comment->delete(); // If you want replies to be deleted along with the comment, // set this in your config file: // 'delete_replies_along_comments' => true,
Advanced Usage
Using Query Scopes
// Get only approved comments $approvedComments = Comment::approved()->get(); // Get comments for a specific model $post = Post::find(1); $postComments = $post->comments()->approved()->latest()->get();
Accessing Comment Relationships
$comment = Comment::find(1); // Get the model that was commented on $commentedModel = $comment->commentable; // Get the user who made the comment $user = $comment->commentator; // Get replies to this comment $replies = $comment->replies; // Get parent comment (if this is a reply) $parent = $comment->parent;
Events
The package dispatches events when comments are created or deleted:
CommentAdded Event
<?php namespace App\Listeners; use NewWaySo\Comments\Events\CommentAdded; class SendCommentNotification { public function handle(CommentAdded $event) { $comment = $event->comment; // Send notification email // Log the comment // Update statistics // etc. } }
CommentDeleted Event
<?php namespace App\Listeners; use NewWaySo\Comments\Events\CommentDeleted; class HandleCommentDeletion { public function handle(CommentDeleted $event) { $comment = $event->comment; // Clean up related data // Update statistics // Send notifications // etc. } }
Register your listeners in EventServiceProvider
:
protected $listen = [ \NewWaySo\Comments\Events\CommentAdded::class => [ \App\Listeners\SendCommentNotification::class, ], \NewWaySo\Comments\Events\CommentDeleted::class => [ \App\Listeners\HandleCommentDeletion::class, ], ];
API Reference
HasComments Trait Methods
Method | Description |
---|---|
comments() |
Returns all comments for the model |
comment($comment) |
Add a comment as the authenticated user |
commentAsUser($user, $comment) |
Add a comment as a specific user |
replyToComment($parentComment, $comment, $user = null) |
Reply to an existing comment |
Comment Model Methods
Method | Description |
---|---|
approve() |
Approve the comment |
disapprove() |
Disapprove the comment |
commentable() |
Get the model that was commented on |
commentator() |
Get the user who made the comment |
parent() |
Get the parent comment (for replies) |
replies() |
Get all replies to this comment |
Query Scopes
Scope | Description |
---|---|
approved() |
Get only approved comments |
Database Structure
The package creates a comments
table with the following structure:
- id (increments) - commentable_id (unsignedBigInteger) - commentable_type (string) - comment (text) - is_approved (boolean, default: false) - user_id (unsignedBigInteger, nullable) - parent_id (unsignedInteger, nullable) - created_at (timestamp) - updated_at (timestamp)
Examples
Complete Example: Blog with Comments
<?php // Models class Post extends Model { use HasComments; protected $fillable = ['title', 'content']; } class User extends Authenticatable implements Commentator { use CanComment; public function needsCommentApproval($model): bool { // Auto-approve comments from verified users return !$this->email_verified_at; } } // Controller class PostController extends Controller { public function show(Post $post) { $post->load([ 'comments' => function ($query) { $query->approved() ->whereNull('parent_id') // Only top-level comments ->with(['commentator', 'replies.commentator']) ->latest(); } ]); return view('posts.show', compact('post')); } public function storeComment(Request $request, Post $post) { $request->validate([ 'comment' => 'required|string|max:1000', 'parent_id' => 'nullable|exists:comments,id' ]); if ($request->parent_id) { $parentComment = Comment::find($request->parent_id); $comment = $post->replyToComment($parentComment, $request->comment); } else { $comment = $post->comment($request->comment); } return back()->with('success', 'Comment added successfully!'); } }
Blade Template Example
{{-- Display comments --}} @foreach($post->comments as $comment) <div class="comment"> <div class="comment-header"> <strong>{{ $comment->commentator->name ?? 'Anonymous' }}</strong> <small>{{ $comment->created_at->diffForHumans() }}</small> </div> <div class="comment-body"> {{ $comment->comment }} </div> {{-- Display replies --}} @foreach($comment->replies as $reply) <div class="reply"> <div class="reply-header"> <strong>{{ $reply->commentator->name ?? 'Anonymous' }}</strong> <small>{{ $reply->created_at->diffForHumans() }}</small> </div> <div class="reply-body"> {{ $reply->comment }} </div> </div> @endforeach </div> @endforeach {{-- Comment form --}} <form method="POST" action="{{ route('posts.comments.store', $post) }}"> @csrf <div class="form-group"> <textarea name="comment" class="form-control" placeholder="Add a comment..."></textarea> </div> <button type="submit" class="btn btn-primary">Post Comment</button> </form>
Testing
Run the tests with:
composer test
Contributing
Please see CONTRIBUTING for details.
Security
If you discover any security related issues, please email security@newway-solution.com instead of using the issue tracker.
Credits
License
The MIT License (MIT). Please see License File for more information.