byrcsc/laravel-comments ยท 1.x
Quick start.
Make a post commentable, write a thread, moderate a guest comment, react, and render the section with the queries a comment list actually runs.
This walkthrough builds a comment section on a Post: an authenticated
comment, a reply, a reaction, a guest comment held for moderation, and the
queries that render the result.
1. Make the model commentable
use ByRcsc\LaravelComments\Concerns\HasComments;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
use HasComments;
}2. Write a comment
$comment = $post->comment('Great write-up!', by: $user);$by is any Eloquent model โ a user, an admin, a bot. The package stores it as
a morph and never assumes it is App\Models\User.
3. Reply to it
$reply = $comment->reply('Agreed, especially the last section.', by: $teammate);
$reply->parent_id; // the comment's key
$reply->depth(); // 1Replies live on the same commentable as their parent and nest up to
comments.max_depth, which is 3 by default. See
threads and replies.
4. React to it
$comment->react('๐', by: $teammate);
$comment->reactionSummary(); // ['๐' => 1]Reacting twice with the same reaction is a no-op that hands back the row that was already there, so a double tap cannot inflate a count. Reactions need an identity, so there is no guest path here. See reactions.
5. Take a guest comment
$guest = $post->commentAsGuest(
'Where can I download the slides?',
name: 'Jane',
email: 'jane@example.com',
);
$guest->status; // CommentStatus::PendingGuest comments start pending whatever comments.default_status says.
Approving anonymous content is a decision the package will not make for you.
See initial status.
6. Moderate it
$guest->approve(by: $moderator);The actor is optional and recorded on the event, not on the comment. Approving
an already-approved comment returns false, writes nothing, and fires nothing.
The other two transitions read the same way:
$spam->markAsSpam(by: $moderator);
$offTopic->reject(by: $moderator);Nothing here hides the comment. Status is package state; visibility is your query. See moderation.
7. Render the thread
$threads = $post->comments()
->approved()
->topLevel()
->with('replies')
->get();approved() is what decides what a visitor reads. topLevel() returns thread
starters, and with('replies') brings each one's direct replies along โ nest
it further (with('replies.replies')) to the depth your interface renders.
To hold announcements at the top of the list, add the pin ordering:
$threads = $post->comments()
->approved()
->topLevel()
->pinnedFirst()
->with(['replies', 'reactionCounts'])
->get();Eager-loading reactionCounts renders every comment's reactions in one query
for the page rather than one per comment.
8. Build a moderation queue
The package ships no queue model, because a scope is one:
$pending = Comment::query()
->pending()
->with('commentable')
->latest()
->paginate();9. Authorize the calls
The engine's own methods never authorize anything โ they work in a queued job, a seeder, and a console command, where there is no authenticated actor to ask about. Enforcement belongs where your application calls the engine:
use ByRcsc\LaravelComments\Models\Comment;
use ByRcsc\LaravelComments\Policies\CommentPolicy;
use Illuminate\Support\Facades\Gate;
// A service provider
Gate::policy(Comment::class, CommentPolicy::class);
// A controller
$this->authorize('approve', $comment);
$comment->approve(by: $request->user());The shipped policy denies every moderation ability by default. Extend it and register yours to say who moderates. See authorization.
10. Escape on output
The body is stored exactly as it arrived. So is the guest name.
{{ $comment->body }}Blade escapes this. Anything that renders markdown or HTML has to sanitize first โ see rendering and safety.
What to read next
- Commentable models for the trait's full surface.
- Moderation for statuses, scopes, and the re-moderation pattern.
- Comment counts for the denormalized count on your own table.
- Events and listeners for everything the package fires.
- Testing for
Comments::fake()and the factories.