I have built a similar solution that uses events and a listener class that dispatches the appropriate notification type
The user has a relationship to an alerts table. This table holds the user_id, the event type, and a comma separated list of via
So, one record per user per event
Then the listener
<?php
namespace App\Listeners;
use App\Digest;
use App\Mail\AlertMail;
use App\Notifications\GeneralAlertNotification;
use App\User;
use Illuminate\Support\Str;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Mail;
class NotifyUsersListener
{
/**
* Handle the event.
*
* @param object $event
* @return void
*/
public function handle($event)
{
// send the event to all the users that are interested.
// except for the user that created it
$users = User::with(['alerts'=>function($query) use($event) {
$query->where('event', class_basename($event));
}])->whereHas('alerts', function($query) use ($event){
$query->where('event', class_basename($event));
})->where('id','!=',Auth::id())
->get();
foreach($users as $user) {
$vias = explode(',',$user->alerts->first()->via ?? '');
foreach($vias as $via) {
if(method_exists($this,$via)) {
$this->$via($event,$user);
}
}
}
}
public function email($event,User $user)
{
Mail::to($user)->queue(new AlertMail($event));
}
public function digest($event,User $user)
{
Digest::create([
'id' => Str::uuid(),
'type' => class_basename($event),
'notifiable_type' => User::class,
'notifiable_id' => $user->id,
'data' => [
'described' => $event->described,
'entityName' => $event->entityName,
'entityId' => $event->entityId,
'showRoute' => $event->showRoute,
],
]);
}
public function internal($event,User $user)
{
$user->notify(new GeneralAlertNotification($event));
}
}
receives the event and gets all users that have an interest in that event by filtering the Alert records to those mentioning the base classname of the event.
Then for each user interested in that event, explode their vias and call the appropriate method.
Mail and database are as they say
Digest is a daily email (sent by cron) for the events that occurred that day.
The only thing I have not really worked out is registering the listeners. There must be a better way than this;
protected $listen = [
Registered::class => [
SendEmailVerificationNotification::class,
],
FoodbankAddedEvent::class => [
NotifyUsersListener::class,
],
FoodbankApprovedEvent::class => [
NotifyUsersListener::class
],
ShipmentCreatedEvent::class => [
NotifyUsersListener::class
],
ShipmentCancelledEvent::class => [
NotifyUsersListener::class
],
ShipmentReceivedEvent::class => [
NotifyUsersListener::class
],
AllocationCompleteEvent::class => [
NotifyUsersListener::class
],
You see the same notification registered for every event (this is only half of the list)