【问题标题】:Laravel: customize or extend notifications - database modelLaravel:自定义或扩展通知 - 数据库模型
【发布时间】:2017-09-24 13:24:01
【问题描述】:

恕我直言,当前在 Laravel 中保存通知的数据库通道设计非常糟糕:

  • 例如,您不能在项目上使用外键级联来清理已删除项目的通知
  • data 列(强制转换为数组)中搜索自定义属性不是最佳选择

您将如何扩展供应商包中的 DatabaseNotification 模型?

我想将列 event_idquestion_iduser_id(创建通知的用户)等添加到默认 laravel notifications 表中

如何覆盖send 函数以包含更多列?

在:

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

代码:

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

【问题讨论】:

    标签: laravel laravel-5 laravel-6


    【解决方案1】:

    创建自定义通知渠道:

    首先,在 App\Notifications 中创建一个 Class 例如:

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

    其次,在Notification类的via方法中使用这个通道:

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

    【讨论】:

    • 太棒了,شكراً جزيلاً
    • 如何从通知变量中获取用户信息?
    • 就我而言,由于某些原因,本机通知表仍在使用中...
    • 不支持驱动程序 [App\Notifications\CustomDatabaseChannel]
    • 对我来说,toDatabase(),toArray() 有效
    【解决方案2】:

    创建并使用您自己的 Notification 模型和 Notifiable 特征,然后在您的(用户)模型中使用您自己的 Notifiable 特征。

    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
    {
        // ...
    }
    

    应用\用户.php:

    namespace App;
    
    use Illuminate\Foundation\Auth\User as Authenticatable;
    
    class User extends Authenticatable
    {
        use Notifiable;
    
        // ...
    }
    

    【讨论】:

      【解决方案3】:

      @cweiske response 的示例。

      如果您确实需要扩展 Illuminate\Notifications\Channels\DatabaseChannel 而不是创建新频道,您可以:

      扩展频道:

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

      并在应用容器上再次注册Illuminate\Notifications\Channels\DatabaseChannel

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

      现在当Illuminate\Notifications\ChannelManager 尝试createDatabaseDriver 将返回您注册的数据库驱动程序。

      更多一个选项来解决这个问题!

      【讨论】:

      • 注册部分对我不起作用,但我发现这篇文章 medium.com/@alouinimedamin/… 并通过将 $this-&gt;app-&gt;make(..Mailer class..)$this-&gt;app-&gt;make(..Markdown class..) 传递给我的覆盖邮件通道类使其工作
      • 我想要改变的是时间戳在 SQL Server 的通知表中的存储方式,这就是重点。通过在create函数中添加'created_at' =&gt; Carbon::now()-&gt;format('Y-d-m H:i:s.0')'updated_at' =&gt; Carbon::now()-&gt;format('Y-d-m H:i:s.0'),已经解决了! Laravel 文档很多时候并没有涵盖所有情况,所以...谢谢大家!
      【解决方案4】:

      与“Bassem El Hachem”不同,我想在 via() 方法中保留 database 关键字。

      因此,除了自定义DatabaseChannel,我还编写了自己的ChannelManager,它在createDatabaseDriver() 方法中返回我自己的DatabaseChannel

      在我的应用程序的 ServiceProvider::register() 方法中,我重写了原始 ChannelManager 类的单例以返回我的自定义管理器。

      【讨论】:

        【解决方案5】:

        我通过自定义通知类解决了类似的问题:

        为此操作创建类:

        artisan make:notification NewQuestion
        

        里面:

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

        然后您可以像这样访问视图或控制器中的适当数据:

        @if($notification->type=='App\Notifications\UserRegistered')
        <a href="{!!route('question.show',$notification->data['question']['id'])!!}">New question from {{$notification->data['user']['name']}}</a>
        @endif
        

        【讨论】:

          猜你喜欢
          • 2017-09-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多