Laravel Notifications are an awesome tool that provides built-in support for sending notifications, in dozens of different channels, like Slack, Telegram, SMS, etc.
In this tutorial, we will see how we can customise Laravel Notifications core to accommodate a multi-tenant setup in a single database.
Note: This tutorial is using Laravel 9.x but should be working for older Laravel versions as well.
Step 1: The Notifications Table
The first thing we need to do is publish the default notifications table using
php artisan notifications:table
You should now have a new migration file under database/migrations which should look like this
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
public function up()
{
Schema::create('notifications', function (Blueprint $table) {
$table->uuid('id')->primary();
$table->string('type');
$table->morphs('notifiable');
$table->text('data');
$table->timestamp('read_at')->nullable();
$table->timestamps();
});
}
};
Ideally, we would like to have a foreign key to the tenant model.
Schema::create('notifications', function (Blueprint $table) {
$table->uuid('id')->primary();
$table->string('type');
$table->morphs('notifiable');
$table->text('data');
$table->timestamp('read_at')->nullable();
$table->timestamps();
$table->foreignId('tenant_id')->constrained(); // <- Add this
});
If tenants are supposed to be receiving notifications you might want to make the tenant_id column nullable.
Step 2: Override Laravel’s Database Channel
The next step would be to find a way to fill in that column whenever a notification is being stored in the database. For that, we need to extend the default DatabaseChannel class and replace our version in the Laravel Container.
What we need is a new class called DatabaseChannel
which extends Illuminate\Notifications\Channels\DatabaseChannel
.
<?php
namespace App\Notifications\Channels;
use Illuminate\Notifications\Notification;
class DatabaseChannel extends \Illuminate\Notifications\Channels\DatabaseChannel
{
public function buildPayload($notifiable, Notification $notification)
{
return [
'id' => $notification->id,
'type' => get_class($notification),
'data' => $this->getData($notifiable, $notification),
'read_at' => null,
'tenant_id' => $notification->tenant_id,
];
}
}
Step 3: Create a tenant-aware Notification
Now, whenever we create a new notification we need to inject the tenant_id property so that we can insert it into the database.
<?php
namespace App\Notifications;
use Illuminate\Notifications\Notification;
class BaseNotification extends Notification
{
public $tenant_id;
public function __construct($tenant_id)
{
$this->tenant_id = $tenant_id;
}
public function via()
{
return ['database'];
}
public function toDatabase($notifiable)
{
return [
// your payload
];
}
}
Step 4: Use our implementation of the DatabaseChannel
Finally, we need to switch Laravel’s implementation of the DatabaseChannel
with ours. To do that we just need to set this up inside the boot method of the AppServiceProvider
.
<?php
namespace App\Providers;
use App\Notifications\Channels\DatabaseChannel;
use \Illuminate\Notifications\Channels\DatabaseChannel as BaseDatabaseChannel;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
$this->app->instance(BaseDatabaseChannel::class, new DatabaseChannel());
}
}
Ready!
And that’s it!
You now have multi-tenant notifications set up in your Laravel project!