Laravel:自定义或扩展通知 - 数据库模型
Posted
技术标签:
【中文标题】Laravel:自定义或扩展通知 - 数据库模型【英文标题】:Laravel: customize or extend notifications - database model 【发布时间】:2017-09-24 13:24:01 【问题描述】:恕我直言,当前在 Laravel 中保存通知的数据库通道设计非常糟糕:
例如,您不能在项目上使用外键级联来清理已删除项目的通知 在data
列(强制转换为数组)中搜索自定义属性不是最佳选择
您将如何扩展供应商包中的 DatabaseNotification
模型?
我想将列 event_id
、question_id
、user_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->app->make(..Mailer class..)
和 $this->app->make(..Markdown class..)
传递给我的覆盖邮件通道类使其工作
我想要改变的是时间戳在 SQL Server 的通知表中的存储方式,这就是重点。通过在create
函数中添加'created_at' => Carbon::now()->format('Y-d-m H:i:s.0')
和'updated_at' => Carbon::now()->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:自定义或扩展通知 - 数据库模型的主要内容,如果未能解决你的问题,请参考以下文章