imagina / inotification
处理实时通知的模块
Requires
- php: ^8.1
- composer/installers: ~1.0
- imagina/core-module: ^10.0
- kawankoding/laravel-fcm: ^0.2.0
- symfony/http-client: ^6.4
- symfony/mailgun-mailer: ^6.4
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.27.0
- orchestra/testbench: ^8.5
- phpunit/phpunit: ^10
Suggests
- pusher/pusher-php-server: Allows notifications to enable real-time notifications.
README
Asgard Notification Module 的改进版本 - https://github.com/AsgardCms/Notification
##发布说明
新增
- 规则
CreateNotificationRequest
- 请求规则的验证消息
Labs Mobile
作为 SMS 通知的默认提供商Provider
、Rule
、Template
和TypeNotification
Asgard 实体 ScaffolddefaultEmailView
配置- 将
provider
和recipient
列添加到notification__notifications
表中 - 将
notificationTypes
配置添加到notification__notification_types
表中 - 添加新的提供商配置的
providers
配置 - 依赖于配置的
NotificationTypeTableSeeder
- 使用
EventServiceProvider
动态监听配置providers
中定义的所有事件 - 使用
NotificationHandler
处理由EventServiceProvider
监听的所有事件 Rule->conditions
验证ImaginaNotification
是AsgardNotification
的改进版本
注意
使用新的
ImaginaNotification
服务,表notification__notifications
中的user_id
列被recipient
列替换
安装
Composer
在终端中执行以下命令
composer require imagina/asgardcms-inotifications
注意
安装后,您需要为获取后端博客模块页面权限提供所需的权限。**
运行迁移和播种器
php artisan module:migrate notification --seed
提供商配置
#####/Config/config.php
提供商字段
配置提供商所需的所有字段:API 密钥、登录、用户名、密码。
每个字段都需要在 basequasar-app 中的 dynamic fields
配置中定义。以下是需要字段列表
注意
每个提供商字段可以定义指向公共配置的路线以替换 ENV 文件中的密钥,只需添加配置Route值
// example: broadcasting pusher config route "configRoute" => "broadcasting.connections.pusher.options.encrypted"
此设置仅在发送通知时使用,其余应用程序将继续使用 .env 文件中的设置。
提供商设置
为每个规则定制提供商字段的必要设置
每个设置都需要在 basequasar-app 中的 dynamic fields
配置中定义。以下是需要设置列表
注意
提供商的必需字段比规则设置具有更高的优先级。
发布配置
php artisan module:publish-config notification
用法
有两种方法可以用来发送通知
###1 快速向您的前端应用程序发送通知。
在您需要的地方注入 Modules\Notification\Services\Inotification
接口并将其分配给类变量。
// New Service Inotification use Modules\Notification\Services\Inotification; /** * by type, to user->id recipient */ $this->notification->type('broadcast')->to($user->id) ->push( [ "title" => "test notification", "message" => "message notification", "icon_class" => "fas fa-test", "link" => url(''), "setting" => [ "saveInDatabase" => 1 // now, the notifications with type broadcast need to be save in database to really send the notification ] ] ); /** * by mutiple types, to user->id recipient */ $this->notification->type(['broadcast', 'push'])->to($user->id) ->push( [ "title" => "test notification", "message" => "message notification", "icon_class" => "fas fa-test", "link" => url(''), "setting" => [ "saveInDatabase" => 1 // now, the notifications with type broadcast need to be save in database to really send the notification ] ] ); /** * by provider, to user->email recipient */ $this->notification->provider('email')->to($user->email) ->push( [ "title" => "test notification", "message" => "message notification", "icon_class" => "fas fa-test", "link" => url(''), "view" => "email.view" ] ); /** * by mutiple types defined in the to */ $this->notification->to([ "broadcast" => $user->id, "email" => $user->email, ])->push( [ "title" => "test notification", "message" => "message notification", "icon_class" => "fas fa-test", "link" => url(''), "view" => "email.view", "setting" => [ "saveInDatabase" => 1 // now, the notifications with type broadcast need to be save in database to really send the notification ] ] );
2 使用事件并定义每个模块中的 Notifiable 配置,通过规则从数据库管理
Notifiable 配置
在模块中首先需要定义可通知配置,通知模块会检测配置并将其发送到前端以创建规则,每个规则都需要保存在数据库中以生效。
可通知条件配置
条件配置类似于basequasar-app的动态字段,但是只有三种类型的条件可用
1 递归
"EMail" => [ "name" => "EMail", 'value' => [ "comparator" => "", "value" => "" ], 'type' => 'recursive', "fields" => [ "operator" => [ "name" => "operator", 'value' => 'any', 'type' => 'select', 'props' => [ 'label' => 'Email', 'options' => [ ['label' => 'Any', 'value' => 'any'], ['label' => 'Contains', 'value' => 'contains'], ['label' => 'Exact Match', 'value' => 'exactMatch'] ] ], ], "value" => [ "name" => "value", 'value' => '', 'type' => 'text', 'props' => [ 'label' => '' ], ], "type" => [ "name" => "type", 'value' => 'comparatorSimple', 'type' => 'hidden', 'props' => [ 'label' => '' ], ] ] ],
2 选择静态选项
"NinetyMin" => [ "name" => "NinetyMin", 'value' => 'any', 'type' => 'select', 'props' => [ 'label' => 'Ninety Min', 'options' => [ ['label' => 'Any', 'value' => 'any'], ['label' => 'Yes', 'value' => 'Y'], ['label' => 'No', 'value' => 'N'] ] ], ],
3 选择动态选项
"idSource" => [ "name" => "idSource", 'value' => 'any', 'type' => 'select', 'loadOptions' => [ 'apiRoute' => 'apiRoutes.setup.sources', 'select' => ['label' => 'title', 'id' => 'id'] ], 'options' => [ ['label' => 'Any', 'value' => 'any'], ], 'props' => [ 'label' => 'Source' ], ],
注意
所有条件都需要设置默认值
any
,处理程序会检测并验证它
##事件示例
namespace Modules\Iteam\Events; class UserWasJoined { public $user; public $team; // this attribute it's required public $entity; /** * Create a new event instance. * * @param $entity * @param array $data */ public function __construct($user,$team) { $this->user = $user; $this->entity = $team; $this->team = $team; } // this method it's required public function notification(){ return [ "title" => "¡Buenas Noticias!, te han aceptado en el equipo: ".$this->team->title, "message" => "Has sido aceptado en el equipo: ".$this->team->title, "icon_class" => "fas fa-glass-cheers", "link" => "link", "view" => "iteam::emails.userJoined.userJoined", "recipients" => [ "email" => [$this->user->email], "broadcast" => [$this->user->id], "push" => [$this->user->id], ], // here you can send all objects and params necessary to the view template "user" => $this->user, "team" => $this->team ]; } }
可通知配置示例
'notifiable' => [ [ "title" => "Lead Opportunity", "entityName" => "Modules\\Ilead\\Entities\\LeadOpportunity", "events" => [ [ "title" => "New Lead Opportunity was created", "path" => "Modules\\Ilead\\Events\\LeadOpportunityWasCreated" ] ], "conditions" => [ "EMail" => [ "name" => "EMail", 'value' => [ "comparator" => "", "value" => "" ], 'type' => 'recursive', "fields" => [ "operator" => [ "name" => "operator", 'value' => 'any', 'type' => 'select', 'props' => [ 'label' => 'Email', 'options' => [ ['label' => 'Any', 'value' => 'any'], ['label' => 'Contains', 'value' => 'contains'], ['label' => 'Exact Match', 'value' => 'exactMatch'] ] ], ], "value" => [ "name" => "value", 'value' => '', 'type' => 'text', 'props' => [ 'label' => '' ], ], "type" => [ "name" => "type", 'value' => 'comparatorSimple', 'type' => 'hidden', 'props' => [ 'label' => '' ], ] ] ], "NinetyMin" => [ "name" => "NinetyMin", 'value' => 'any', 'type' => 'select', 'props' => [ 'label' => 'Ninety Min', 'options' => [ ['label' => 'Any', 'value' => 'any'], ['label' => 'Yes', 'value' => 'Y'], ['label' => 'No', 'value' => 'N'] ] ], ], "idSource" => [ "name" => "idSource", 'value' => 'any', 'type' => 'select', 'loadOptions' => [ 'apiRoute' => 'apiRoutes.setup.sources', 'select' => ['label' => 'title', 'id' => 'id'] ], 'options' => [ ['label' => 'Any', 'value' => 'any'], ], 'props' => [ 'label' => 'Source' ], ], "idStore" => [ "name" => "idStore", 'value' => 'any', 'type' => 'select', 'loadOptions' => [ 'apiRoute' => 'apiRoutes.setup.stores', 'select' => ['label' => 'title', 'id' => 'id'] ], 'options' => [ ['label' => 'Any', 'value' => 'any'], ], 'props' => [ 'label' => 'Store' ], ], ], "settings" => [ "email" => [ "recipients" => [ ['label' => 'Customer Email', 'value' => 'EMail'] ] ], "sms" => [ "recipients" => [ ['label' => 'Day Phone', 'value' => 'DayPhone'], ['label' => 'Evening Phone', 'value' => 'EvePhone'], ['label' => 'Cell Phone', 'value' => 'CellPhone'] ] ], "pusher" => [ "recipients" => [ ['label' => 'Rep 1', 'value' => 'repId'], ['label' => 'Rep 2', 'value' => 'repId2'] ] ], "firebase" => [ "recipients" => [ ['label' => 'Rep 1', 'value' => 'repId'], ['label' => 'Rep 2', 'value' => 'repId2'] ] ], ], ], ]
提供者配置示例 提供者
"pusher" => [// PUSHER PROVIDER "name" => "Pusher", "systemName" => "pusher", "icon" => "far fa-bell", "color" => "#c223ce", "rules" => [ "numeric", "min:1", ], "fields" => [ "id" => [ 'value' => null, ], "pusherAppEncrypted" => [ "name" => "pusherAppEncrypted", 'value' => true, 'type' => 'toggle', "isFakeField" => 'fields', 'props' => [ 'label' => 'Pusher App Encrypted', 'falseValue' => false, 'trueValue' => true ], "configRoute" => "broadcasting.connections.pusher.options.encrypted" ], "pusherAppId" => [ "name" => "pusherAppId", 'value' => '', 'type' => 'input', "isFakeField" => 'fields', 'required' => true, 'props' => [ 'label' => 'Pusher App Id *' ], "configRoute" => "broadcasting.connections.pusher.app_id" ], "pusherAppKey" => [ "name" => "pusherAppKey", 'value' => '', 'type' => 'input', "isFakeField" => 'fields', 'required' => true, 'props' => [ 'label' => 'Pusher App Key *' ], "configRoute" => "broadcasting.connections.pusher.key" ], "pusherAppSecret" => [ "name" => "pusherAppSecret", 'value' => '', 'type' => 'input', "isFakeField" => 'fields', 'required' => true, 'props' => [ 'label' => 'Pusher App Secret *' ], "configRoute" => "broadcasting.connections.pusher.secret" ], "pusherAppCluster" => [ "name" => "pusherAppCluster", 'value' => '', 'type' => 'input', "isFakeField" => 'fields', 'required' => true, 'props' => [ 'label' => 'Pusher App Cluster *' ], "configRoute" => "broadcasting.connections.pusher.options.cluster" ], "status" => [ "name" => "status", 'value' => '0', 'type' => 'select', 'required' => true, 'props' => [ 'label' => 'Status', 'options' => [ ["label" => 'enabled', "value" => '1'], ["label" => 'disabled', "value" => '0'], ], ], ], "default" => [ "name" => "default", 'value' => false, 'type' => 'checkbox', 'props' => [ 'label' => 'Default', ] ], "saveInDatabase" => [ "name" => "saveInDatabase", 'value' => '1', 'type' => 'select', 'required' => true, 'props' => [ 'label' => 'Save in database', 'options' => [ ["label" => 'enabled', "value" => '1'], ["label" => 'disabled', "value" => '0'], ], ], ], "type" => ['value' => 'broadcast'], ], "settings" => [ "recipients" => [ "name" => "recipients", 'value' => '', 'type' => 'input', "isFakeField" => 'settings', 'props' => [ 'label' => 'Recipients', "hint" => "Enter recipient ID - separate entries with commas" ], ], "status" => [ "name" => "status", 'value' => '0', 'type' => 'select', 'required' => true, 'props' => [ 'label' => 'Enable', 'options' => [ ["label" => 'enabled', "value" => '1'], ["label" => 'disabled', "value" => '0'], ], ], ], "saveInDatabase" => [ "name" => "saveInDatabase", 'value' => '1', 'type' => 'select', 'required' => true, 'props' => [ 'label' => 'Save in database', 'options' => [ ["label" => 'enabled', "value" => '1'], ["label" => 'disabled', "value" => '0'], ], ], ], ] ],