Laravel: customize or extend notifications - database model

BassMHL picture BassMHL · Apr 27, 2017 · Viewed 13.1k times · Source

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,
    ]);
 }
}

Answer

BassMHL picture BassMHL · Apr 27, 2017

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
    ];
  }
}