newway-solutions/laravel-comments

Add comments to your Laravel application

1.0.0 2025-09-07 12:10 UTC

This package is auto-updated.

Last update: 2025-09-07 12:34:16 UTC


README

Latest Version on Packagist MIT Licensed Total Downloads

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.