Laravel:自定义或扩展通知 - 数据库模型

Posted

技术标签:

【中文标题】Laravel:自定义或扩展通知 - 数据库模型【英文标题】:Laravel: customize or extend notifications - database model 【发布时间】: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,
    ]);
 

【问题讨论】:

【参考方案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

【讨论】:

以上是关于Laravel:自定义或扩展通知 - 数据库模型的主要内容,如果未能解决你的问题,请参考以下文章

laravel5异常及时通知

在 Laravel 7 测试中使用自定义测试模型

如何使用 laravel 发送自定义电子邮件通知?

android,如何检查或查找活动通知匹配自定义数据

根据自定义用户区域设置值发送 Laravel 通知

Laravel 在包中使用自定义 USER-Model