yzh52521/think-notification

The Notification Library For ThinkPHP6

v2.0.2 2023-08-28 06:50 UTC

This package is auto-updated.

Last update: 2024-04-28 08:28:38 UTC


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 
{
     // ...
}