Laravel Notifications — Part 2: Creating a custom notification channel

Syed Sirajul Islam Anik
5 min readJun 12, 2020

--

Image from: https://csshint.com/wp-content/uploads/2019/07/CSS-Notification-Bell-Icon.jpg

In part 1, I discussed how Laravel notifications work. I tried my best to give a thorough picture of the concept. Check out part 1 from the link below.

In this article, we’ll discuss how to create your own custom notification channel if you have to create one.

The channel in Laravel Notification is not the same as the Laravel Broadcasting channel. There is a command available for creating channel but the channel is for Broadcasting not for notification channel. Creating a channel is easy.

We’ll write a new channel for notification which will write to the log file. If you get the concept, then you can create channels for your own purpose. Let’s create a new class for our purpose. Let’s name it LogChannel and put it in the app/Channels directory. So, our class will look like the following.

<?php

namespace App\Channels;

class LogChannel
{

}

Now, we need to register our Channel. You can use an existing Service provider to register the channel. Otherwise, create a new service provider and register that provider in config/app.php's providers array. We’ll use AppServiceProvider class to register our channel.

<?php
namespace App\Providers;
use App\Channels\LogChannel;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
// Edit: It previously named as `register`.
// Correction: Should be under `boot` method.
public function boot()
{
// The log will be used in the Notification's via method
// You can use whatever name your want
Notification::extend('log', function ($app) {
return new LogChannel();
});
}
}

Now to comply with Laravel’s rule for channels, we need to implement one method send in our LogChannel class which will receive $notifier Model instance & Notification $notification class instance as parameters. So, our class will now look like below.

<?php

namespace App\Channels;

use Illuminate\Notifications\Notification;

class LogChannel
{
public function send ($notifiable, Notification $notification) {

}
}

In the send method, we will now have to implement our logic. If you create your own sms channel, then you’ll need to implement the logic here.

Now, it’s up to you how you want to get the identifier where you want to send the notification data. Suppose, you want to send an SMS, then you’ll need the mobile number or if you want to send an email, then you’ll look for email id. So, let’s put that concern to $notifiable class. We’ll look for a method from where we’ll get the identifiable data. And you need data to send to that user or model owner. So, we’ll put that concern to the Notification implementer class. All we need to do is to call those methods and if things are good, we’ll pass that information to the receiver. Let’s do it in the code.

<?php

namespace App\Channels;

use Illuminate\Notifications\Notification;

class LogChannel
{
public function send ($notifiable, Notification $notification) {

if (method_exists($notifiable, 'routeNotificationForLog')) {
$id = $notifiable->routeNotificationForLog($notifiable);
} else {
$id = $notifiable->getKey();
}

$data = method_exists($notification, 'toLog')
? $notification->toLog($notifiable)
: $notification->toArray($notifiable);
if (empty($data)) {
return;
}
app('log')->info(json_encode([
'id' => $id,
'data' => $data,
]));
return true;
}
}

So, the above snippet checks for the routeNotificationForLog method in our model instance. If the method is not defined in our model, then it collects the primary key for that model as an identifier ($id). Next, it looks for the toLog method in our $notification instance. If the model is not defined, then it looks for the toArray method. if the data is empty, we’ll not log anything in our log file. Otherwise, we’ll just put the id and data as json in our log file.

So, the User model (In this context. You can have your desired model) will now implement the routeNotificationForLog method. And our notification will implement the toLog method. So the code will be as follows.

  • app/User.php class
<?phpnamespace App;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

class User extends Authenticatable
{
use Notifiable;

public function routeNotificationForLog ($notifiable) {
return 'identifier-from-notification-for-log: ' . $this->id;
}
}
  • app/Notifications/LogNotification.php class
<?php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;

class LogNotification extends Notification
{
use Queueable;

public function __construct () { }

public function via ($notifiable) {
// The name we used when registering in the provider
return [ 'log' ];

// Alternatively, if not registered in service provider
// return [ \App\Channels\LogChannel::class ];
}

public function toLog ($notifiable) {
return [
'from' => 'to-log',
'notifiable-id' => $notifiable->id,
];
}

public function toArray ($notifiable) {
return [
'from' => 'to-array',
'notifiable-id' => $notifiable->id,
];
}
}

So in our codebase, if we call like the following.

// ... from a controller// Approach 1
$user->notify(new LogNotification());
// Approach 2
// Notification::send($user, new LogNotification());

The output will be

Output for LogNotification. Implemented User::routeNotificationForLog() & LogNotification::toLog()

When removed User::routeNotificationForLog method, the output becomes

Output for LogNotification. Removed User::routeNotificationForLog() & Implemented LogNotification::toLog()

And when we removed LogNotification::toLog method, the output becomes

Output for LogNotification. Removed User::routeNotificationForLog() & LogNotification::toLog()

The send method of your Channel class is responsible for sending the notification. All your sending logic should be in that method. You can use whatever suits your need.

Last tip

  • If you don’t register your channel class in any service provider, then you can use the class name style to refer to your channel. But I more like to register my channel in servicer providers.
  • If you don’t use default or shipped channels as your notification mediums and you don’t use $model->notify($notification) format to send notifications, then you don’t need to use the Notifiable trait in your models. It needs to be there if you use notify or notifyNow method from your model or use database or mail as drivers. And yes, if you community-driven packages, then you may need to use the trait.

Don’t forget to check my first article on Laravel notifications.

Happy coding. ❤

--

--

Syed Sirajul Islam Anik

software engineer with "Senior" tag | procrastinator | programmer | !polyglot | What else 🙄 — Open to Remote