Click to share! ⬇️

Mentions And Notifications

Community based websites often times allow you to mention another user by screen name. For example, if you post a message to Twitter and include a user’s name including the @ symbol, then the user will get a notification that you mentioned them. This tutorial will recreate that type of feature in the forum based application we have been building. In the replies area of threads, if a user types in a reply and includes @Tom as an example, then when Tom logs into his account he should see a notification in the upper right navigation bar area to alert him that he has a thread to check out.

Mentioned Users Test

We can start by creating a feature test and we’ll name it MentionUsersTest.
mentioned users test case

What do we want this test to do? Well it should test for notifications to mentioned users. Here is the pseudo code.

  • Given we have a user Tom that is signed in
  • Given we also have a user named Sarah
  • If we have a thread
  • Then Tom replies to that thread and mentions @Sarah
  • Then @Sarah should receive a notification

With these goals in mind, we can create the test_mentioned_users_in_a_reply_are_notified() method in the MentionUsersTest class.


namespace TestsFeature;

use IlluminateFoundationTestingDatabaseMigrations;
use TestsTestCase;
use IlluminateFoundationTestingWithFaker;
use IlluminateFoundationTestingRefreshDatabase;

class MentionUsersTest extends TestCase
    use DatabaseMigrations;

    function test_mentioned_users_in_a_reply_are_notified()
        // Given we have a user Tom that is signed in.
        $tom = create('AppUser', ['name' => 'Tom']);

        // Given we also have a user named Sarah.
        $sarah = create('AppUser', ['name' => 'Sarah']);

        // If we have a thread
        $thread = create('AppThread');

        // Then Tom replies to that thread and mentions @Sarah.
        $reply = make('AppReply', [
            'body' => 'Hey @Sarah check this out.'
        $this->json('post', $thread->path() . '/replies', $reply->toArray());

        // Then @Sarah should receive a notification.
        $this->assertCount(1, $sarah->notifications);

So we have the test, but no supporting code yet. We know if will fail, but we can let the errors help us in building the code to make it work. Currently we are getting an error of “Failed asserting that actual size 0 matches expected size 1.”

vagrant@homestead:~/Code/forumio$ phpunit --filter test_mentioned_users_in_a_reply_are_notified
PHPUnit 6.5.5 by Sebastian Bergmann and contributors.

F                                                                   1 / 1 (100%)

Time: 1.61 seconds, Memory: 10.00MB

There was 1 failure:

1) TestsFeatureMentionUsersTest::test_mentioned_users_in_a_reply_are_notified
Failed asserting that actual size 0 matches expected size 1.


Tests: 1, Assertions: 1, Failures: 1.

How can we make this work? Consider when a user fills out the form to submit a reply. Maybe the user includes a name like @Tom in that text. As that body of text gets processed, the application needs to inspect the body of the reply text for user name mentions. If one or more is found, then those users should get a notification. So we need a function that will fetch all mentioned users within the reply’s body. This is a great job for regular expressions. We’ll add a mentionedUsers() method in the Reply model that leverages PHP’s preg_match_all() function.


namespace App;

use IlluminateDatabaseEloquentModel;

class Reply extends Model
    use Favoriteable, RecordsActivity;

    protected $guarded = [];

    protected $with = ['owner', 'favorites'];

    protected $appends = ['favoritesCount', 'isFavorited'];

    public function owner()
        return $this->belongsTo(User::class, 'user_id');

    public function thread()
        return $this->belongsTo(Thread::class);

    public function mentionedUsers()
        preg_match_all('/@([w-]+)/', $this->body, $matches);
        return $matches[1];

    public function path()
        return $this->thread->path() . '#reply-' . $this->id;

Create A Notification Class

We recently set up notifications for users that are subscribed to specific threads. So we have an idea of how to set up notifications in Laravel. Recall that we can use artisan to scaffold out a Notification class for us.

vagrant@homestead:~/Code/forumio$ php artisan make:notification YouWereMentioned
Notification created successfully.

notification class created

The code we can use in this new notification class is here. It’s worth paying attention to the highlighted section of the toArray() method. The contents of that method become the actual message or notification which gets stored in the database. Again, we had customized this method during our subscriber notifications tutorial, but now we need to tweak things a bit for this user mentions tutorial. Also note that we are accepting the $reply variable as a protected property in this class. That is the reply for which a user was mentioned in. This class needs access to that reply in order to do it’s job.


namespace AppNotifications;

use IlluminateBusQueueable;
use IlluminateNotificationsNotification;

class YouWereMentioned extends Notification
    use Queueable;

    protected $reply;

    public function __construct($reply)
        $this->reply = $reply;

    public function via($notifiable)
        return ['database'];

    public function toArray($notifiable)
        return [
            'message' => $this->reply->owner->name . ' mentioned you in ' . $this->reply->thread->title,
            'link' => $this->reply->path()

Using An Event To Notify A User

We are already firing an event in the addReply() method of the Thread model.

public function addReply($reply)
    $reply = $this->replies()->create($reply);

    event(new ThreadReceivedNewReply($reply));

    return $reply;

In addition to that, we have listener set up for that event which handles notifications for subscribed users. Wouldn’t it be cool if we could simply add another listener that would handle notifying mentioned users as well? That is exactly what we’ll do here. We’ll simply add a new listener to the array as highlighted here. Now, when the ThreadReceivedNewReply fires, both NotifySubscribers and NotifyMentionedUsers will handle that event.


namespace AppProviders;

use IlluminateFoundationSupportProvidersEventServiceProvider as ServiceProvider;

class EventServiceProvider extends ServiceProvider
    protected $listen = [
        'AppEventsThreadReceivedNewReply' => [

    public function boot()

Once again we can run php artisan event:generate to scaffold out our new class file.

vagrant@homestead:~/Code/forumio$ php artisan event:generate
Events and listeners generated successfully!

Now we see the new NotifyMentionedUsers class in the Listeners directory.
php artisan event generate

Now within the handle() method, we implement the logic to notify a user when they were mentioned.


namespace AppListeners;

use AppEventsThreadReceivedNewReply;
use AppNotificationsYouWereMentioned;
use AppUser;

class NotifyMentionedUsers
    public function handle(ThreadReceivedNewReply $event)
        User::whereIn('name', $event->reply->mentionedUsers())
            ->each(function ($user) use ($event) {
                $user->notify(new YouWereMentioned($event->reply));

It looks like the test is now passing!

vagrant@homestead:~/Code/forumio$ phpunit --filter test_mentioned_users_in_a_reply_are_notified
PHPUnit 6.5.5 by Sebastian Bergmann and contributors.

.                                                                   1 / 1 (100%)

Time: 1.53 seconds, Memory: 10.00MB

OK (1 test, 1 assertion)

User Mention Notification Lifecycle

To summarize, here is how the lifecycle of a user mention notification works.

A user adds a new reply, and an event is fired. This happens in addReply() of Thread.php.

new reply added fires event

The announcement to the application that a thread has received a new reply is made by the ThreadReceivedNewReply event class.

event announcement class

Now, in EventServiceProvider, it is configured that when ThreadReceivedNewReply makes an announcement, then NotifyMentionedUsers will respond to that. In fact NotifySubscribers will also respond, but in this scenario we are more concerned with NotifyMentionedUsers responding. The mapping between an event firing and a listener responding happens here.

event and listener mapping

Now the listener takes over and handles that announcement that was made. Or in other words, it handles the event.

the listener handles the event

Within the code above, we see it leans on that mentionedUsers() method which exists on the Reply model. This syntax is kind of a fancy way to check for all mentioned users, then look them up in the database.

preg match all finds mentioned users

Then for each one you find, a notification is made via YouWereMentioned notification class.

user was mentioned notification class

Putting The Rubber To The Road

Ok it’s time to put the rubber to the road so to speak. We want to actually test this out in the browser and see what happens. First off, we’ll log in as the user Sarah and find a thread where we can respond to Tom. We’ll at mention him with the @Tom syntax and tell him his recipe is great.
new at mention of a user

Now we just go log in as user Tom and we should see a new notification. In fact we do! We see that Sarah mentioned us in the “Holy Guacamole!” thread. Very Cool!
successful user notification received

Mentions And Notifications Summary

This tutorial built upon our knowledge of events and notifications in Laravel to set up a new notification system for mentioned users. Now you are armed with the knowledge of how to create your own user mention notification system like you see on many popular social websites.

Click to share! ⬇️