Laravel 5.4, 5.3: настройка или расширение уведомлений - модель базы данных
ИМХО, текущий канал базы данных для сохранения уведомлений в Laravel действительно плохой дизайн:
- Нельзя использовать каскады внешних ключей для элементов, например, для очистки уведомлений об удаленных элементах.
- Поиск пользовательских атрибутов в
data
столбец (приведенный к массиву) не является оптимальным
Как бы вы пошли о продлении DatabaseNotification
Модель в упаковке продавца?
Я хотел бы добавить столбцы event_id
, question_id
, user_id
(пользователь, создавший уведомление) и т. д. по умолчанию 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,
]);
}
}
6 ответов
Чтобы создать собственный канал уведомлений:
Сначала создайте класс в 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,
]);
}
}
Во-вторых, используйте этот канал в 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
];
}
}
Создать и использовать свой собственный Notification
модель и 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
{
// ...
}
App \ User.php:
namespace App;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use Notifiable;
// ...
}
Пример ответа @cweiske.
Если вам действительно нужно продлить 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
вернет ваш зарегистрированный драйвер базы данных.
Еще один вариант решения этой проблемы!
В отличие от "Bassem El Hachem", я хотел сохранить database
Ключевое слово в via()
методы.
Так в дополнение к обычаю DatabaseChannel
Я тоже написал свой ChannelManager
это возвращает мой собственный DatabaseChannel
в createDatabaseDriver()
метод.
В моих приложениях ServiceProvider::register()
метод, я переписал синглтон для исходного класса ChannelManager, чтобы вернуть мой пользовательский менеджер.
Вы можете ввести значения новых столбцов на уровне модели, прослушиваяcreating
событие.
- Установите уведомление.
namespace App\Notifications;
use Illuminate\Notifications\Notification;
class YourNotification extends Notification
{
// ...
public function toArray($notifiable): array
{
return [
'new_column' => 'value',
'serializable_data' => $serializable_data,
];
}
}
- Создайте свою собственную модель уведомлений и отредактируйте то, что вставляется.
namespace App\Models;
use Illuminate\Notifications\DatabaseNotification;
class Notification extends DatabaseNotification
{
protected static function booted(): void
{
static::creating(function (Notification $notification) {
$data = $notification->data;
$notification->new_column = $data['new_column'];
unset($data['new_column']);
$notification->data = $data;
});
}
}
- Переопределить связь в модели пользователя.
public function notifications()
{
return $this->morphMany(Notification::class, 'notifiable')->orderBy('created_at', 'desc');
}
По моему мнению, уведомления Laravel еще не готовы и имеют очень ограниченные функциональные возможности.
В любом случае, я решил похожую проблему, настроив класс уведомлений:
создайте класс для этого действия:
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