Let’s play with Laravel Notifications

Introduction
Let’s explore the realm of Laravel, a robust PHP framework, to examine mail and database notifications and understand their implementation. In this article, we will also discuss the process of creating and sending these notifications. Laravel, designed by Taylor Otwell, is a widely used framework that equips developers with a diverse set of tools and features to facilitate the construction of contemporary websites. Our emphasis in this discussion will be on Laravel’s notification system, particularly in the context of database and mail notifications.
Technical requirements:
1. PHP 8.1
2. MySQL 8.0
3. Laravel 10
Project setup
First, we will need to create a new Laravel project:
composer create-project laravel/laravel laravel-notifications
We will also be using Laravel Sail which is a lightweight CLI for dealing with the Laravel Docker environment. Sail is optional, you can just proceed without it. The difference will be that instead of using the sail prefix in commands, you’ll use the php prefix.
Sail is already been added, so we only need to run:
php artisan sail: install
After running Sail installation, it’s going to ask us a question about which services we would like to install. We will pick MySQL but you can pick any that Sail offers. Let the Sail build run, and once it’s successful we have our Sail project setup.
We only need to run this in our project directory:
./vendor/bin/sail up
Since we are going to be sending notifications on the registration of users, we will be using Laravel Breeze as our starter kit to provide authentication. This will give us authentication out of the box, so we don’t need to create our own.
For configuration Breeze we need to run:
composer require laravel/breeze --dev
After we install Breeze, it will ask us some configuration questions, these are not important as you can use notifications in this tutorial with any of the Breeze stacks. So you can pick whichever you want.
Which stack would you like to install? Blade.
Would you like to install dark mode support? Yes.
Would you prefer Pest tests instead of PHPUnit? No.
After installation is complete, we only need to run commands to finish breeze installation:
sail artisan migrate sail npm install sail npm run dev
Mail notifications
Starting with mail notifications, we first need to set up send mail configuration in our environment file. For caching our test mails, we will be using Mailtrap, but you can use any service you want. This is how our configuration should look in .env file:
MAIL_FROM_ADDRESS="[email protected]"
MAIL_FROM_NAME="${APP_NAME}"
MAIL_MAILER=smtp
MAIL_HOST=sandbox.smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=username
MAIL_PASSWORD=password
MAIL_ENCRYPTION=tls
For mail notifications, we are going to create a notification to send a welcome mail to the users when they register for an account.
For creating notifications we use the make:notification command, with the name of the notification. This will create a notification folder in our app directory with the created notification.
Let’s create our first notification:
sail artisan make:notification WelcomeNotification
Let’s go over our newly created WelcomeNotification. Firstly, we have the via() method, in which we specify what channel we are going to be using to send the notification. This includes mail, database, Slack, SMS, or any community channel. We can also add custom channels ourselves. We can specify more than one channel, or using the $notifiable, we can specify some custom conditions to determine which channel will the notification be sent to.
public function via(object $notifiable): array
{
return ['mail'];
}
or
public function via(object $notifiable): array
{
return $notifiable->prefers_mail ? ['mail'] : ['mail', 'database'];
}
We also have the toMail and toArray methods. We will use these methods to configure what to send when we notify.
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->line('The introduction to the notification.')
->action('Notification Action', url('/'))
->line('Thank you for using our application!');
}
public function toArray(object $notifiable): array
{
return [
//
];
}
Since we are focusing on mail notifications, we need to define a toMail method that returns a MailMessage instance. We can customize a lot of information, like specifying from, subject, greeting, lines, and calls to action. We can even attach one or multiple files as well as add tags and metadata. If we need to customize the Laravel mail template provided, we can do so by publishing the package resources:
php artisan vendor:publish --tag=laravel-notifications
For now, we will only be sending a mail message, for which we only need to specify mail in the via method. For the message, we will add a form address, subject, greeting, and line. We will also add a call to action which will lead to the dashboard of our application. This call to action will render a button in our mail, which will take us to the defined URL.
public function __construct()
{
//
}
public function via(object $notifiable): array
{
return ['mail'];
}
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->from('[email protected]', 'Welcome')
->subject('Welcome notification.')
->greeting(sprintf('Hello %s!', $notifiable->name))
->line('Welcome to our app!')
->action('Visit dashboard', url('/dashboard'));
}
To send the notifications, there are two ways, one is by using the notify method specified in the Notifiable trait, which is being used by our User model. And the other is by using the notification facade.
We will be using the first method as our User model is already using the notifiable trait. So in our Controllers\Auth\RegisteredUserController we can add the notify call after auth login.
public function store(Request $request): RedirectResponse
{
// code
Auth::login($user);
$user->notify(new WelcomeNotification());
// code
}
We can test it now, and if we register with a new account, we will get the welcome mail in our testing Mailtrap inbox.
Database notifications
One other option is to save the notification to the database. This is useful when we want to display notifications to our users in our app interface.
To use database notifications, we first need to create a table to hold the notifications in the database. To do that, we only need to run:
php artisan notifications:table
php artisan migrate
Laravel will then create the notifications table in our database of choice.
Let’s go over some of the columns that were created. We will have the type of notification, in our example, this will be the NewPostCreatedNotifications. The Notifiable type is the User model, with the notifiable id which is our User id. In the data column, we will be saving the data from our notification as encoded JSON. And lastly, we have the read-at column which we can use to mark the notification as read by the user.
Before we create our database notification we will need some setup, as we will be sending a notification to users’ followers after the user creates a post. To do this, let’s first create a post and followers table migration:
php artisan make:migration create_posts_table
php artisan make:migration create_followers_table
// Posts table
public function up(): void
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id');
$table->foreign('user_id')->references('id')->on('users');
$table->string('title', 255);
$table->text('body');
$table->timestamps();
});
}
// Followers table
public function up(): void
{
Schema::create('followers', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('followed_id');
$table->foreign('followed_id')->references('id')->on('users');
$table->unsignedBigInteger('follower_id');
$table->foreign('follower_id')->references('id')->on('users');
$table->timestamps();
});
}
php artisan migrate
Now let’s create a database seeder so that we have some test data. We will create a seeder that creates one main user and three follower users. For creating a seeder we need to run:
php artisan make:seeder FollowerSeeder
But before we do this, let’s add the follower’s relationship to the user class.
public function followers(): BelongsToMany
{
return $this->belongsToMany(User::class, 'followers', 'followed_id', 'follower_id');
}
In the seeder, we will create a main user, with which we can log in so we need to make sure the mail is unique.
public function run(): void
{
$mainUser = User::factory()->create([
'email' => '[email protected]',
]);
$followers = User::factory()->count(3)->create();
$mainUser->followers()->sync($followers->pluck('id'));
Let’s seed the database with our users:
php artisan db:seed --class=FollowerSeeder
Now let’s create a post controller and a model so that we can send the notification to notify our followers about a new post.
php artisan make:model Post
php artisan make:controller PostController
Finally, let’s make the notification, in this case, it will be called NewPostCreatedNotification.
php artisan make:notification NewPostCreatedNotification
Now let’s configure our new notification. We will pass a post to the notification so that we can notify which post was created. We will also set the via method to the database. And we will configure the toArray method to save the title of the post to the database in the data column.
We can use the toArray or toDatabase methods to save data in the database, the difference is that the toArray method is also used for broadcasting to your frontend. We can also use both of these methods if we have a difference in what we want to broadcast and what to save in the database.
For now, we will only be using the toArray method.
public function __construct(private Post $post)
{
//
}
public function via(object $notifiable): array
{
return ['database'];
}
public function toArray(object $notifiable): array
{
return [
'title' => $this->post->title,
];
}
This time, to send our notification we will be using the notification facade. The difference is that it’s used mainly when you need to send a notification to a collection of users. Which is the case here.
Let’s send our notification in the PostController:
public function store(Request $request): RedirectResponse
{
$post = new Post();
$post->user_id = Auth::user()->id;
$post->title = $request->title;
$post->body = $request->body;
$post->save();
$followers = Auth::user()->followers;
Notification::send($followers, new NewPostCreatedNotification($post));
return back()->with('success', 'You created a new post!');
We will create a new post, get authenticated users’ followers, and send the notification to them.
That’s it, if we check our database we will see the new entries with the post title in our data column.
Another thing to cover is accessing the notifications, we can do that easily because of the Notifiable trait in our User model, which offers methods of accessing the notifications via eloquent relationships. Here are some methods for accessing our Notifiable trait:
// Get all notifications
$user->notifications
// Get unread notifications
$user->unreadNotifications
// Mark all user notifications as read
$user->unreadNotifications->markAsRead();
// Delete all user notifications
$user->notifications()->delete();
Notification Faking
Aside from MailSlurp, you can use the Notification facade’s fake method. It simulates the mail delivery process and allows you to confirm whether an email would have arrived in the recipient’s inbox. Check out how it works:
<?php
namespace App\Notifications;
use App\User;
use App\Notifications\StatusUpdate;
use Illuminate\Support\Facades\Notification;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
class StatusUpdate extends User
{
public function testStatusOrder()
{
Notification::fake();
// Perform status order...
Notification::assertSentTo(
$user,
NewPostCreatedNotification::class,
function ($notification, $channels) use ($sale) {
// retrieve the mail content
$mailData = $notification->toMail($user)->toArray();
$this->assertEquals("Order #{$sale->saleNumber} sold", $mailData['subject']);
$this->assertEquals("Hello {$user->name}!", $mailData['greeting']);
$this->assertContains("Your item #{$sale->saleNumber} has been sold", $mailData['introLines']);
$this->assertEquals("View items", $mailData['actionText']);
$this->assertEquals(route('orders.show', $sale), $mailData['actionUrl']);
$this->assertContains("Thanks!", $mailData['outroLines']);
return $notification->order->id === $sale->id;
}
);
}
}
Various assertions are shown here to test the mail content. They are generated after the code under test has been executed.
Conclusion
And there it is, we covered mail and database notifications, with this being just a small overview of the Laravel notifications system. Laravel offers even more notifications like SMS, Slack, etc.
Some other interesting topics
Stay tuned!!! I will be back with some more cool Laravel tutorials in the next article. I hope you liked the article. Don’t forget to follow me 😇 and give some claps 👏. And if you have any questions feel free to comment. Thank you.
Thanks a lot for reading till the end. Follow or contact me via: Email: [email protected] Github: https://github.com/reubenshumba LinkedIn: https://www.linkedin.com/in/reuben-shumba-a72aaa157/ BuyMeCoffee: https://www.buymeacoffee.com/reubenshumba REUBEN SHUMBA