byrcsc/laravel-comments · 1.x
Commentable models.
The HasComments trait, writing comments as a model or as a guest, and the columns a comment carries.
Any Eloquent model becomes commentable by adding one trait. This page covers what that trait gives you and what a comment row holds.
use ByRcsc\LaravelComments\Concerns\HasComments;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
use HasComments;
}There is no registration step and no interface to implement. The trait adds a polymorphic relation and two write methods.
Write a comment
comment() takes a body and the model writing it:
$comment = $post->comment('Great write-up!', by: $user);$by is any Eloquent model. The package stores commentator_type and
commentator_id as a morph and never assumes a user class.
commentAsGuest() takes a name and an email instead:
$comment = $post->commentAsGuest(
'Where can I download the slides?',
name: 'Jane',
email: 'jane@example.com',
);A comment carries exactly one of the two identities. A guest comment has a null
commentator_type, which is how the package tells them apart — and why guest
comments have their own default status, cannot react, and are never notified.
Both methods throw a CommentableNotPersistedException when the commentable
has not been saved yet. There is nothing for the comment to point at.
Read comments
$post->comments; // every comment, any status, any depth
$post->comments()->count();The relation is a plain MorphMany, so everything you know about Eloquent
applies. Narrow it with the scopes:
$post->comments()->approved()->topLevel()->with('replies')->get();| Scope | Returns |
|---|---|
topLevel() | Thread starters — comments with no parent |
pending() | Comments waiting on a moderator |
approved() | Comments in the approved set |
rejected() | Comments a moderator turned down |
spam() | Comments marked as spam, kept apart from rejected |
pinned() | Comments held at the top of their thread |
pinnedFirst() | Ordering: pinned first, most recently pinned among them |
Soft-deleted comments are excluded by Eloquent's own global scope; reach them
with withTrashed(). See deleting comments.
What a comment holds
| Column | Meaning |
|---|---|
commentable_type, commentable_id | The record being commented on |
commentator_type, commentator_id | Who wrote it, or null for a guest |
guest_name, guest_email | The guest identity, or null for a model-authored comment |
parent_id | The comment being replied to, or null at the top |
body | Stored verbatim, untrusted input |
status | pending, approved, rejected, or spam |
edited_at | When the body last changed, or null |
pinned_at | When it was pinned, or null |
reply_notified_at | When its author was told about it, or null |
deleted_at | Soft-delete tombstone marker |
status casts to a CommentStatus enum; the four timestamps cast to Carbon.
Relations on a comment
$comment->commentable; // the record it is on
$comment->commentator; // the model that wrote it, or null for a guest
$comment->parent; // the comment it replies to, or null
$comment->replies; // direct replies only
$comment->reactions; // every reaction row
$comment->reactionCounts; // grouped counts, for rendering
$comment->revisions; // prior bodies, oldest first
$comment->attachments; // attachment metadata, oldest firstAsk who wrote it
$comment->isBy($user); // boolBoth halves of the morph have to match: a User and an Admin that happen to
share a primary key are not the same author. A guest-authored comment matches
nobody, which is what makes ownership checks deny for one.
Optional: keep a count
A commentable can keep a denormalized count of its approved, non-deleted comments on its own table. It is off until you override one method and add the column yourself:
public function commentsCountColumn(): ?string
{
return 'comments_count';
}See comment counts for the migration, the maintenance guarantees, and the repair command.
Optional: decide the initial status
A commentable can implement DecidesCommentStatus to say what status its new
comments start in, overriding both configured defaults. See
initial status.