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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/43646085/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 15:52:01  来源:igfitidea点击:

Laravel: customize or extend notifications - database model

laravellaravel-5laravel-6

提问by BassMHL

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

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

  • You can't use foreign key cascades on items for cleaning up notifications of a deleted item for example
  • Searching custom attributes in the datacolumn (casted to Array) is not optimal
  • 例如,您不能在项目上使用外键级联来清理已删除项目的通知
  • data列中搜索自定义属性(转换为数组)不是最佳选择

How would you go about extending the DatabaseNotificationModel in vendor package?

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

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

我想添加列event_idquestion_iduser_id(在创建该通知用户)等等为默认laravelnotifications

How do you override the sendfunction to include more columns?

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

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

回答by BassMHL

To create a custom Notification Channel:

要创建自定义通知渠道:

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

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

<?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 viamethod in the Notification class:

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

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

回答by Kamal Khan

Create and use your own Notificationmodel and Notifiabletrait and then use your own Notifiable trait in your (User) models.

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

App\Notifiable.php:

应用\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:

应用\Notification.php:

namespace App;

use Illuminate\Notifications\DatabaseNotification;

class Notification extends DatabaseNotification
{
    // ...
}

App\User.php:

应用\用户.php:

namespace App;

use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use Notifiable;

    // ...
}

回答by cweiske

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

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

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

所以除了自定义之外DatabaseChannel,我还编写了自己的ChannelManagerDatabaseChannelcreateDatabaseDriver()方法中返回我自己的。

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

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

回答by Samuel Martins

An example for @cweiske response.

@cweiske response的示例。

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

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

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\DatabaseChannelon application container again:

Illuminate\Notifications\Channels\DatabaseChannel再次注册应用程序容器:

app\Providers\AppServiceProvider.php

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\ChannelManagertry createDatabaseDriverwill return your registered database driver.

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

More one option to solve this problem!

解决这个问题的更多选择!

回答by Luca C.

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