byrcsc/laravel-comments · 1.x
Events and listeners.
Every event the package fires, what each carries, and the two rules that decide how you listen to them.
Every event carries the comment it happened to, so a listener that only cares
which record moved can type-hint the base class CommentEvent and be done.
Everything else — the thread, the commentable, the commentator — is derivable
from the comment.
Events fire whether or not any of the package's own features are switched on. Your listeners are never coupled to its config.
The full list
Lifecycle
| Event | Fires when |
|---|---|
CommentCreated | A comment or reply is written, guest or not |
CommentUpdated | Any saved change: a body edit, a transition, a pin, a restore |
CommentDeleted | A soft delete, and also a force delete |
CommentRestored | A tombstone is restored |
CommentForceDeleted | A comment is removed for good |
CommentForceDeleted additionally carries $countableRemoved: how many
comments in the removed subtree were approved and not soft deleted. See
deleting comments.
Moderation — base CommentModerated
| Event | Fires when |
|---|---|
CommentApproved | approve() moved it |
CommentRejected | reject() moved it |
CommentMarkedAsSpam | markAsSpam() moved it |
Each carries $previousStatus and $actor (null when nobody was named).
Reactions — base CommentReacted
| Event | Fires when |
|---|---|
ReactionAdded | A reaction row actually appeared |
ReactionRemoved | One actually went away |
Each carries $reactor and $reaction.
Attachments — base CommentAttachmentChanged
| Event | Fires when |
|---|---|
AttachmentAdded | A row is recorded |
AttachmentRemoved | detach() removes one, or a force delete takes one |
Each carries $attachment.
Pinning — base CommentPinChanged
| Event | Fires when |
|---|---|
CommentPinned | A pin actually went up |
CommentUnpinned | One actually came down |
Each carries $actor.
Rule one: listen by concrete class
Laravel's dispatcher resolves listeners by interface but never by parent class.
Listening to CommentModerated alone would never fire — name the concrete
events and type-hint the base:
use ByRcsc\LaravelComments\Events\CommentApproved;
use ByRcsc\LaravelComments\Events\CommentMarkedAsSpam;
use ByRcsc\LaravelComments\Events\CommentModerated;
use ByRcsc\LaravelComments\Events\CommentRejected;
use Illuminate\Support\Facades\Event;
Event::listen(
[CommentApproved::class, CommentRejected::class, CommentMarkedAsSpam::class],
fn (CommentModerated $event) => $this->reindex($event->comment),
);The same applies to CommentReacted, CommentAttachmentChanged,
CommentPinChanged, and CommentEvent: useful as type hints, never as
subscriptions.
Rule two: one event means one real change
Re-entering a status writes nothing and fires nothing. Pinning a pinned comment does the same. Reacting twice with the same reaction hands back the existing row and fires nothing. Detaching an attachment that is already gone fires nothing.
That is a guarantee you can build on: a listener counting approvals counts real ones, and a notification cannot double up under a double click.
The events also fire only once the write is known to have landed. A host
saving listener that halts the save leaves nothing counting a state change the
table never took.
Queue anything slow
Events fire inside whatever transaction caused them, synchronously. A listener that does anything slow or external should be queued, and a queued listener should dispatch after commit — the comment it was handed may still be rolled back:
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Contracts\Events\ShouldDispatchAfterCommit;
class IndexComment implements ShouldQueue, ShouldDispatchAfterCommit
{
public function handle(CommentCreated $event): void
{
// ...
}
}What fires and what does not
The lifecycle events ride Eloquent's own model events, so anything that skips
those skips these: saveQuietly(), the query builder, raw SQL. The moderation,
reaction, attachment, and pin events are dispatched by the package itself,
immediately after the write.
CommentUpdated is the one to watch for edits, because it fires for every kind
of update. Ask the comment which kind it was:
Event::listen(CommentUpdated::class, function (CommentUpdated $event): void {
if ($event->comment->wasChanged('body')) {
// an edit — the revision for it is already filed
}
});The package's own listeners
Two subscribers are registered unconditionally, and both ask their question per comment rather than at boot — so a config change takes effect without a reboot:
MaintainsCommentCountskeeps an opted-in commentable's count honest. A model that never opted in costs an array lookup. See comment counts.SendsReplyNotificationstells a comment's author that somebody replied. Nothing is sent unless the config says so. See reply notifications.