@mentions
Comment bodies are scanned for @handle tokens on write and edit. Handles are always stored as CommentMention rows; set a resolver to link them to models and fire CommentMentioned. The resolver is a class, not a closure — php artisan config:cache cannot store a closure:
// app/Mentions/ResolveMention.php
namespace App\Mentions;
use App\Models\User;
final class ResolveMention
{
public function __invoke(string $handle): ?User
{
return User::where('username', $handle)->first();
}
}
// config/comments.php — an invokable class, or [ResolveMention::class, 'someMethod']
'mention_resolver' => \App\Mentions\ResolveMention::class,
$comment = Comments::on($post)->body('thanks @alice!')->post();
$comment->mentions; // CommentMention rows (handle + optional mentionable)- A handle is @ followed by letters, digits, _, . or - (@john.doe), but it ends on a letter, digit or underscore — so “thanks @alice.” mentions alice. It must not follow a word character, so an email address like [email protected] is not a mention.
- The resolver receives the handle without the @ and returns an Eloquent model or null. It is built through the container, so it may take constructor dependencies.
When CommentMentioned fires
- Only for an approved comment, once per person. A comment the moderation layer holds back — require_approval, a blocklist pending or hidden match, a moderator’s hide — notifies nobody until Comments::approve(); then each resolved mention fires once.
- Each handle is stored once per comment. An edit fires it only for people the comment has not notified yet — handles still in the body keep their rows, removed ones are deleted, and re-mentioning the same person, even under another handle, is not a new mention.
- A hide-and-approve round trip never notifies anyone twice.
A [class, method] resolver
Instead of an invokable class, point the resolver at a [Class::class, 'method'] pair. The class is built through the container too, so the pair stays config:cache-safe:
// config/comments.php
'mention_resolver' => [App\Support\MentionResolver::class, 'resolve'],
// app/Support/MentionResolver.php — built through the container
namespace App\Support;
use App\Models\User;
final class MentionResolver
{
public function resolve(string $handle): ?User
{
return User::where('username', $handle)->first();
}
}Notifying mentioned users
use Illuminate\Support\Facades\Event;
use RoundlyConsulting\Comments\Events\CommentMentioned;
Event::listen(function (CommentMentioned $event): void {
$event->mention->handle; // 'alice'
$event->mention->mentionable; // the resolved model (e.g. your User)
$event->mention->comment; // the Comment that mentions them
});Show your open-source love
This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.
More ways to support, including cryptoBy donating, you agree to our donation terms.
Want this built into your product?
We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.