yzh52521 / think-notification
The Notification Library For ThinkPHP6
Requires
- php: >=8.0.2
- symfony/uid: ^6.0
Requires (Dev)
- topthink/framework: >=6.0
- topthink/think-migration: ^3.0
- topthink/think-queue: ^3.0
- yzh52521/easyhttp: ^1.0
- yzh52521/think-mailer: ^3.0
- yzh52521/think-sms: ^1.0
Suggests
- topthink/think-migration: create database table
- yzh52521/think-mailer: mail channel
README
支持mail
sms
easysms
database
等驱动
应用场景
发送手机验证码
发送验证邮件,找回密码邮件 订单状态变更
站内消息通知
...
安装
composer require yzh52521/think-notification
创建通知
通常每个通知都由一个存储在 app/notifications 目录下的一个类表示。如果在你的应用中没有看到这个目录,不要担心,当运行 make:notification 命令时它将为您创建:
php think make:notification InvoicePaid
这个命令会在 app/notifications 目录下生成一个新的通知类。每个通知类都包含一个 channels 方法以及一个或多个消息构建的方法比如 toMail 或 toDatabase,它们会针对特定的渠道把通知转换为对应的消息。
发送通知
使用 Notifiable Trait
通知可以通过两种方式发送: 使用 Notifiable 特性的 notify 方法或使用 Notification 门面
<?php namespace app\model; use yzh52521\notification\Notifiable; class User { use Notifiable; }
此 notify 方法需要接收一个通知实例参数:
use app\notification\InvoicePaid; $user->notify(new InvoicePaid($invoice));
请记住,你可以在任何模型中使用 Notifiable trait。而不仅仅是在 User 模型中。
使用 Notification Facade
另外,你可以通过 Notification facade 来发送通知,它主要用在当你需要给多个可接收通知的实体发送的时候,比如给用户集合发送通知。使用 Facade 发送通知的话,要把可接收通知实例和通知实例传递给 send 方法:
use yzh52521\facade\Notification; Notification::send($users, new InvoicePaid($invoice));
您也可以使用 sendNow 方法立即发送通知。即使通知实现了 ShouldQueue 接口,该方法也会立即发送通知:
Notification::sendNow($developers, new DeploymentCompleted($deployment));
发送指定频道
每个通知类都有一个 channels 方法,用于确定将在哪些通道上传递通知。通知可以在 mail、database、sms、easysms 频道上发送。
channels 方法接收一个 $notifiable 实例,这个实例将是通知实际发送到的类的实例。你可以用 $notifiable 来决定这个通知用哪些频道来发送:
/** * 获取通知发送频道 * * @param mixed $notifiable * @return array */ public function channels($notifiable) { return $notifiable->prefers_sms ? ['sendcloud'] : ['mail', 'database']; }
通知队列化
注意:使用通知队列前需要配置队列并 开启一个队列任务。
发送通知可能是耗时的,尤其是通道需要调用额外的 API 来传输通知。为了加速应用的响应时间,可以将通知推送到队列中异步发送,而要实现推送通知到队列,可以让对应通知类实现 ShouldQueue 。如果通知类是通过 make:notification 命令生成的,你可以快速将它们添加到通知类:
<?php namespace app\notifications; use think\queue\ShouldQueue; use yzh52521\Notification; use yzh52521\notification\message\Mail; use yzh52521\notification\Notifiable; class InvoicePaid extends Notification implements ShouldQueue { // ... }
一旦 ShouldQueue 接口被添加到您的通知中,您就可以像往常一样发送通知。 Thinkphp 将检测类上的 ShouldQueue 接口并自动将通知的传递排队:
$user->notify(new InvoicePaid($invoice));
如果您想延迟通知的传递,您可以设置 delay:
public function __construct(Order $order) { $this->order = $order; $this->delay =5; }
自定义通知队列连接: 默认情况下,排队通知将使用应用程序的默认队列连接进行排队。如果您想为特定通知指定一个不同的连接,您可以在通知类上定义一个 $connection 属性:
public function __construct(Order $order) { $this->order = $order; public $connection = 'redis'; $this->delay =5; }
邮件通知
composer require yzh52521/think-mailer
格式化邮件信息
如果通知支持作为电子邮件发送,您应该在通知类上定义一个 toMail 方法。 此方法将接收一个 $notifiable 实体并应返回一个 yzh52521\notification\message\Mail 实例。
Mail 类包含一些简单的方法来帮助您构建事务性电子邮件消息。 邮件消息可能包含文本行以及「动作的调用」。让我们看一个示例 toMail 方法:
/** * 获取通知的邮件描述。 * * @param mixed $notifiable * @return \yzh52521\notification\messages\Mail */ public function toMail($notifiable) { $url = url('/invoice/'.$this->invoice->id); return (new Mail) ->greeting('Hello!') ->line('你的一张发票已经付款了!') ->action('查看发票', $url) ->line('感谢您使用我们的应用程序!'); }
自定义模板 使用 view() 不需要使用 greeting 、 line 、action 等参数 在 view 第二个参数传递
public function toMail($notifiable) { return (new Mail) ->to($to) ->subject('找回密码') ->view('emails.name', ['invoice' => $this->invoice]); }
自定义发件人 默认情况下, 发件人地址在 config/mail.php 配置文件中定义。但是,您可以使用 from 方法指定特定通知的发件人地址:
public function toMail($notifiable) { return (new Mail) ->from('barrett@example.com', 'Barrett Blair') ->line('...'); }
其他用法 参考 yzh52521/think-mailer
数据库通知
必要条件 database 通知通道将通知信息存储在数据库表中。此表将包含通知类型等信息以及描述通知的 JSON 数据结构。 使用的模型必须 use HasDatabaseNotification Trait
您可以查询该表以在应用程序的用户界面中显示通知。但是,在您这样做之前,您需要创建一个数据库表来保存您的通知。您可以使用 notifications:table 命令生成具有正确表模式的 migration:
php think notification:table php think migrate:run
格式化数据库通知#
如果通知支持存储在数据库表中,则应在通知类上定义 toDatabase 方法。这个方法将接收一个 $notifiable 实体并且应该返回一个普通的 PHP 数组。 返回的数组将被编码为 JSON 并存储在 notifications 表的 data 列中。让我们看一个示例 toDatabase 方法:
public function toDatabase($notifiable) { return [ 'invoice_id' => $this->invoice->id, 'amount' => $this->invoice->amount, ]; }
访问通知
一旦通知存储在数据库中,您需要一种方便的方式从您的通知实体访问它们. 必须实现 model 之前的关联关系
$user = app\model\User::find(1); foreach ($user->notifications as $notification) { echo $notification->notification_type; }
如果您只想检索「未读」通知,可以使用 unreadNotifications 关系。同样,这些通知将按 create_time 时间戳排序,最近的通知位于集合的开头:
$user = app\model\User::find(1); foreach ($user->unreadNotifications as $notification) { echo $notification->notification_type; }
将通知标记为已读# 通常,您希望在用户查看通知时将其标记为 “已读”。 yzh52521\notification\Notifiable trait 提供了 markAsRead 方法,它更新通知数据库记录中的 read_time 列:
$user = app\model\User::find(1); foreach ($user->unreadNotifications as $notification) { $notification->markAsRead(); }
但是,您可以直接在通知集合上使用 markAsRead 方法,而不是循环遍历每个通知:
$user->unreadNotifications->markAsRead();
您还可以使用批量更新查询将所有通知标记为已读,而无需从数据库中检索它们:
$user = app\model\User::find(1); $user->unreadNotifications()->update(['read_time' => now()]);
您可以 delete 通知以将它们从表中完全删除:
$user->notifications()->delete();
短信通知
SMS 通知由 Sendcloud 提供支持
必要条件 $user 发件人 $key sendcloud 申请的key
依赖扩展
composer require yzh52521/easyhttp
public function toSendcloud($notifiable) { return (new Sendcloud($user,$key)) ->data('Your SMS message content'); }
格式化短信通知
public function toSendcloud($notifiable) { return (new Sendcloud($user,$key)) ->data('Your SMS message content'); }
收件人 to()
public function toSendcloud($notifiable) { return (new Sendcloud($user,$key)) ->to('15556666666') ->data('Your SMS message content'); }
短信模版 template()
public function toSendcloud($notifiable) { return (new Sendcloud($user,$key)) ->to('15556666666') ->template('40438') ->data('Your SMS message content'); }
设置为彩信 isMultimedia()
public function toSendcloud($notifiable) { return (new Sendcloud($user,$key)) ->to('15556666666') ->isMultimedia() ->data('Your SMS message content'); }
设为语音短信 isVoice()
public function toSendcloud($notifiable) { return (new Sendcloud($user,$key)) ->to('15556666666') ->isVoice() ->data('Your SMS message content'); }
easysms 短信通知
依赖扩展 yzh52521/think-sms
composer require yzh52521/think-sms
sms 配置
config/sms.php
$config = [ // HTTP 请求的超时时间(秒) 'timeout' => 5.0, // 默认发送配置 'default' => [ // 网关调用策略,默认:顺序调用 'strategy' => \Overtrue\EasySms\Strategies\OrderStrategy::class, // 默认可用的发送网关 'gateways' => [ 'aliyun', ], ], // 可用的网关配置 'gateways' => [ 'errorlog' => [ 'file' => '/tmp/easy-sms.log', ], 'aliyun' => [ 'access_key_id' => '', 'access_key_secret' => '', 'sign_name' => '', ], //... ], ];
创建通知
namespace app\notification; use yzh52521\notification\message\Easysms; class ValidateCode extends Notification { public function channels($notifiable) { return ['easysms']; } public function toEasysms($notifiable) { return ( new Easysms ) ->to('13188888888') ->template('SMS_001') ->content('您的验证码{$code},该验证码5分钟内有效,请勿泄漏于他人!') ->data(['code' =>6379]); } }
自定义频道
think-notification 提供了一些通知频道,但你可能想编写自己的驱动程序,以通过其他频道传递通知。要开始,定义一个包含 send 方法的类。该方法应接收两个参数:$notifiable 和 $notification 在 send 方法中,你可以调用通知上的方法来检索一个由你的频道理解的消息对象,然后按照你希望的方式将通知发送给 $notifiable 实例:
namespace app\notification; use yzh52521\notification\Notifiable; use yzh52521\notification\Channel; use yzh52521\Notification; class VoiceChannel extends Channel { /** * 发送给定的通知 * @param Notifiable $notifiable * @param Notification $notification * @return mixed */ public function send($notifiable, Notification $notification): void { $message = $notification->toVoice($notifiable); // 将通知发送给 $notifiable 实例... } }
一旦你定义了你的通知频道类,你可以从你的任何通知的 channels 方法返回该类的名称。在这个例子中,你的通知的 toVoice 方法可以返回你选择来表示语音消息的任何对象。例如,你可以定义自己的 VoiceMessage 类来表示这些消息:
use yzh52521\Notification; use yzh52521\notification\Notifiable; class InvoicePaid extends Notification { /** * 获取通知频道 * @param Notifiable $notifiable */ public function channels( $notifiable) { return VoiceChannel::class; } /** * 获取通知的语音表示形式 * @param Notifiable $notifiable */ public function toVoice($notifiable): VoiceMessage { // ... } }
自定义 VoiceMessage
class VoiceMessage { // ... }