Laravel: customize or extend notifications - database model

前端 未结 5 1391
我在风中等你
我在风中等你 2020-12-03 08:11

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 noti
相关标签:
5条回答
  • 2020-12-03 08:53

    I solved a similar problem by customizing notification class:

    create the class for this action:

    artisan make:notification NewQuestion
    

    inside it:

    public function __construct($user,$question)
        {
            $this->user=$user;
            $this->question=$question;
        }
    
    
    ...
    
        public function toDatabase($notifiable){
            $data=[
                'question'=>$this->(array)$this->question->getAttributes(),
                'user'=>$this->(array)$this->user->getAttributes()
            ];
    
            return $data;
        }
    

    then you can access proper data in view or controller like this:

    @if($notification->type=='App\Notifications\UserRegistered')
    <a href="{!!route('question.show',$notification->data['question']['id'])!!}">New question from {{$notification->data['user']['name']}}</a>
    @endif
    
    0 讨论(0)
  • 2020-12-03 08:55

    Unlike "Bassem El Hachem", I wanted to keep the database keyword in the via() methods.

    So in addition to a custom DatabaseChannel, I also wrote my own ChannelManager that returns my own DatabaseChannel in the createDatabaseDriver() method.

    In my apps' ServiceProvider::register() method, I overwrote the singleton for the original ChannelManager class to return my custom manager.

    0 讨论(0)
  • 2020-12-03 08:57

    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
        ];
      }
    }
    
    0 讨论(0)
  • 2020-12-03 09:05

    An example for @cweiske response.

    If you really need extends the Illuminate\Notifications\Channels\DatabaseChannel not creating a new Channel you can:

    Extends the channel:

    <?php
    
    namespace App\Notifications;
    
    use Illuminate\Notifications\Channels\DatabaseChannel as BaseDatabaseChannel;
    use Illuminate\Notifications\Notification;
    
    class MyDatabaseChannel extends BaseDatabaseChannel
    {
        /**
         * Send the given notification.
         *
         * @param  mixed  $notifiable
         * @param  \Illuminate\Notifications\Notification  $notification
         * @return \Illuminate\Database\Eloquent\Model
         */
        public function send($notifiable, Notification $notification)
        {
            $adminNotificationId = null;
            if (method_exists($notification, 'getAdminNotificationId')) {
                $adminNotificationId = $notification->getAdminNotificationId();
            }
    
            return $notifiable->routeNotificationFor('database')->create([
                'id' => $notification->id,
                'type' => get_class($notification),
                'data' => $this->getData($notifiable, $notification),
    
                // ** New custom field **
                'admin_notification_id' => $adminNotificationId,
    
                'read_at' => null,
            ]);
        }
    }
    
    

    And register the Illuminate\Notifications\Channels\DatabaseChannel on application container again:

    app\Providers\AppServiceProvider.php

    class AppServiceProvider extends ServiceProvider
    {
        /**
         * Bootstrap any application services.
         *
         * @return void
         */
        public function boot()
        {
            //
        }
    
        /**
         * Register any application services.
         *
         * @return void
         */
        public function register()
        {
            $this->app->bind(
                Illuminate\Notifications\Channels\DatabaseChannel::class,
                App\Notifications\MyDatabaseChannel::class
            );
        }
    }
    
    

    Now when the Illuminate\Notifications\ChannelManager try createDatabaseDriver will return your registered database driver.

    More one option to solve this problem!

    0 讨论(0)
  • 2020-12-03 09:08

    Create and use your own Notification model and Notifiable trait and then use your own Notifiable trait in your (User) models.

    App\Notifiable.php:

    namespace App;
    
    use Illuminate\Notifications\Notifiable as BaseNotifiable;
    
    trait Notifiable
    {
        use BaseNotifiable;
    
        /**
         * Get the entity's notifications.
         */
        public function notifications()
        {
            return $this->morphMany(Notification::class, 'notifiable')
                                ->orderBy('created_at', 'desc');
        }
    }
    

    App\Notification.php:

    namespace App;
    
    use Illuminate\Notifications\DatabaseNotification;
    
    class Notification extends DatabaseNotification
    {
        // ...
    }
    

    App\User.php:

    namespace App;
    
    use Illuminate\Foundation\Auth\User as Authenticatable;
    
    class User extends Authenticatable
    {
        use Notifiable;
    
        // ...
    }
    
    0 讨论(0)
提交回复
热议问题