Laravel - Storing notification settings per user with different channels

Viewed 1002

I am developing a fairly simple application, where I want my users to be able to subscribe to notifications. So the system should:

  • Send notifications when a certain event they are subscribed to happens.
  • Send notifications to the channels they have selected (email or slack)

Below is an example of different notifications they each user can subscribe to.

enter image description here

I am wondering how to do this using Laravel. My first idea was to:

  1. Create a notifications JSON column on the users table, and store it like (probably using the learnings from the Managing Mass User Settings lesson.)
{
  "todo": {
    "assigned": [
      {
        "email": true,
        "slack": true
      }
    ],
    "mentioned": [
      {
        "email": true,
        "slack": true
      }
    ]
  },
  "project": {
    "created": [
      {
        "email": true,
        "slack": true
      }
    ]
  }
}

However, I am unsure if this is good practice. Further, I am also a unsure on how to actually send out the notifications dynamically.

For sending it out, I want to use Laravels notification system:

Notification::send($user, new TodoCreated($todo));

I am not sure if this is the best way, or if it makes more sense to use an Event/Listener setup? A

Also, can I utilize the via() method on the Notification class to dynamically specify the channels according to the user settings?

Any input would be greatly appreciated.

1 Answers

I think a many-to-many relationship would be more suited to this.

Tables:

User
 - id

Notifications
 - id

NotificationUser <-- pivot table
 - notifcation_id
 - user_id
 - channel_id

Channel
 - id
 - name 

To account for these additional fields in the pivot table, define them in the User model relationship:

class User extends Model
{
    /**
     * The roles that belong to the user.
     */
    public function notifications()
    {
        return $this->belongsToMany(Notification::class)->withPivot(['channel_id']);
    }
}

See: https://laravel.com/docs/8.x/eloquent-relationships#retrieving-intermediate-table-columns

This way, you can advantage of the relationship methods that Laravel (eloquent) comes with.

i.e:

aUser->notifications(); # Getting a list of a user's notifications
aUser->attach(1, ['channel' => 1]); # attaching a notification to the user

You can also take advantage of query scopes to retrieve one channel of notifications for the user etc

See: https://laravel.com/docs/8.x/eloquent#query-scopes

Then use the model/listener pattern as you had planned.

Related