Search code examples
laravellaravel-5laravel-6

Laravel: customize or extend notifications - database model


IMHO, the current Database channel for saving notifications in Laravel is really bad design:

  • You can't use foreign key cascades on items for cleaning up notifications of a deleted item for example
  • Searching custom attributes in the data column (casted to Array) is not optimal

How would you go about extending the DatabaseNotification Model in vendor package?

I would like to add columns event_id, question_id, user_id (the user that created the notification) etc... to the default laravel notifications table

How do you override the send function to include more columns?

In:

vendor/laravel/framework/src/Illuminate/Notifications/Channels/DatabaseChannel.php

The code:

class DatabaseChannel
{
 /**
  * Send the given notification.
  *
  * @param  mixed  $notifiable
  * @param  \Illuminate\Notifications\Notification  $notification
  * @return \Illuminate\Database\Eloquent\Model
  */
 public function send($notifiable, Notification $notification)
 {
    return $notifiable->routeNotificationFor('database')->create([
        'id' => $notification->id,
        'type' => get_class($notification),

      \\I want to add these
        'user_id' => \Auth::user()->id,
        'event_id' => $notification->type =='event' ? $notification->id : null, 
        'question_id' => $notification->type =='question' ? $notification->id : null,
      \\End adding new columns

        'data' => $this->getData($notifiable, $notification),
        'read_at' => null,
    ]);
 }
}

Solution

  • To create a custom Notification Channel:

    First, create a Class in App\Notifications for example:

    <?php
    
    namespace App\Notifications;
    
    use Illuminate\Notifications\Notification;
    
    class CustomDbChannel 
    {
    
      public function send($notifiable, Notification $notification)
      {
        $data = $notification->toDatabase($notifiable);
    
        return $notifiable->routeNotificationFor('database')->create([
            'id' => $notification->id,
    
            //customize here
            'answer_id' => $data['answer_id'], //<-- comes from toDatabase() Method below
            'user_id'=> \Auth::user()->id,
    
            'type' => get_class($notification),
            'data' => $data,
            'read_at' => null,
        ]);
      }
    
    }
    

    Second, use this channel in the via method in the Notification class:

    <?php
    
    namespace App\Notifications;
    
    use Illuminate\Notifications\Notification;
    
    use App\Notifications\CustomDbChannel;
    
    class NewAnswerPosted extends Notification
    {
      private $answer;
    
      public function __construct($answer)
      {
        $this->answer = $answer;
      }
    
      public function via($notifiable)
      {
        return [CustomDbChannel::class]; //<-- important custom Channel defined here
      }
    
      public function toDatabase($notifiable)
      {
        return [
          'type' => 'some data',
          'title' => 'other data',
          'url' => 'other data',
          'answer_id' => $this->answer->id //<-- send the id here
        ];
      }
    }