mayocube/craft-notifications

通过多种渠道发送通知,包括邮件和Slack。通知也可以存储在数据库中,以便在您的网页界面中显示。

5.0.0 2024-08-17 12:42 UTC

This package is auto-updated.

Last update: 2024-09-19 07:18:50 UTC


README

icon

Craft CMS 5.x 的通知插件

通过多种渠道发送通知,包括邮件和Slack。通知也可以存储在数据库中,以便在您的网页界面中显示。

  1. 安装
  2. 简介
  3. 发送通知
  4. 数据库通知
    1. 检索通知
    2. 标记通知为已读
  5. 删除通知
  6. 邮件通知
  7. Slack通知
    1. 格式化Slack通知
    2. 自定义发件人与收件人
    3. Slack附件
    4. Markdown附件内容
  8. 通知事件
  9. 自定义频道

支持开源。买啤酒。

此插件根据MIT许可证授权,这意味着它是完全免费的开放源代码软件,您可以使用它来做什么和如何使用。如果您在使用它并希望支持开发,请在Beerpay上为我买一杯啤酒!

要求

此插件需要Craft CMS 5.0.0或更高版本。

安装

要安装插件,请按照以下说明操作。

  1. 打开您的终端并转到您的Craft项目

     cd /path/to/project
    
  2. 然后告诉Composer加载插件

     composer require mayocube/craft-notifications
    
  3. 在控制面板中,转到设置→插件,并单击“安装”按钮安装通知。

  4. config.php 文件复制到您的应用程序中的 config/notifications.php

  5. 通过向您的 composer.json 添加以下内容并运行 composer dump -o 来确保您的通知被自动加载。

"autoload": {
    "psr-4": {
        "app\\notifications\\": "./notifications"
    }
},

简介

通常,通知应该是简短的信息性消息,通知用户您的应用程序中发生的事情。例如,如果您正在编写账单应用程序,您可能通过电子邮件和短信渠道向用户发送“发票已支付”的通知。

创建通知

每个通知由一个单独的类表示(存储在您的应用程序的 notifications 目录中)。您必须手动创建它,或者当您运行 notifications/make 命令时,它会为您创建。

./craft notifications/make BlogPostAdded

此命令将在您的 notifications 目录中放置一个新的通知类。每个通知类都包含一个 via 方法以及一系列用于构建消息的方法(例如 toMailtoDatabase),这些方法将通知转换为针对特定渠道优化的消息。

发送通知

通知可以通过两种方式发送,一种是从配置文件,在 event 触发时发送,另一种是从您自己的插件发送。

首先,让我们看看如何配置在例如添加新博客文章时发送通知

<?php 
 
return [
    'notifications' => [
        [
            'class' => \craft\elements\Entry::class,
            'event' => \craft\elements\Entry::EVENT_AFTER_SAVE,
            'notification' => \app\notifications\BlogPostAdded::class,
        ],
    ],
];

这里我们在Craft的 Entry 类的 EVENT_AFTER_SAVE 事件上监听,这将导致我们每次保存条目时触发我们的通知。

在我们的 BlogPostAdded 类中,我们可以使用 via 函数来确定是否以及如何发送通知

/**
 * Get the notification's delivery channels.
 *
 * @return array
 */
public function via()
{
    $entry = $this->event->sender;

    if ($entry->section->handle === 'blog' && $this->event->isNew) {
        return [
            'database' => Craft::$app->getUsers()->getUserByUsernameOrEmail('hello@percipio.london'),
        ];
    }

    return [];
}

我们知道事件是 ElementEvent,它包含 senderisNew 属性,使用这些信息我们可以确定只有当条目来自 blog 部门且是新的条目时,我们才发送通知。

从插件发送通知

从插件中,您可以使用 notificationsService 发送您自己的通知。

use percipioglobal\notifications\Notifications; 
use app\notifications\BlogPostAdded; 
 
Notifications::getInstance()->notificationsService->send(new BlogPostAdded());

数据库通知

为了在数据库中保存通知以便以后检索,请确保您的 via 方法返回一个包含 User 对象的值的 database 键。

return [
    'database' => Craft::$app->getUsers()->getUserByUsernameOrEmail('hello@percipio.london'),
];

当使用 database 通知通道时,您的 Notification 类应该定义一个 toDatabasetoArray 函数。

这可以非常简单,例如

public function toDatabase()
{
    return ArrayHelper::toArray($this);
}

在模板中从数据库检索通知时,通知将包含这里传递的数据。

检索通知

通知插件提供了一个模板变量来检索通知并将它们标记为已读。

让我们看看如何遍历通知,这将自动使用当前登录用户来查找通知

  {% for notification in craft.notifications.unread %}
    {# The notification object contains all the data from the toDatabase or toArray function on your notification class #}
  {% endfor %}

您也可以通过 notificationsService 获取通知

use percipioglobal\notifications\Notifications; 

// All unread notifications
Notifications::getInstance()->notificationsService->getAllUnread();

// All read notifications
Notifications::getInstance()->notificationsService->getAllRead();

// All notifications
Notifications::getInstance()->notificationsService->getAll();

标记通知为已读

要将通知标记为已读,我们可以使用 Twig 变量或 notificationsService。此函数期望一个通知数组。

  {% for notification in craft.notifications.unread %}
    {{ craft.notifications.markAsRead(notification) }}
  {% endfor %}
use percipioglobal\notifications\Notifications; 

Notifications::getInstance()->notificationsService->markAsRead($notification);

删除已读通知

为了保持数据库干净整洁,您可以删除超过特定时间框架的已读通知。默认时间设置为 -1 month。如果您想自定义时间框架,请提供在 strtotime PHP 限制内的日期。

./craft notifications/remove-notifications/index --time="-3 months"

邮件通知

要配置一个作为电子邮件发送的通知,请确保在 Notification 类的 via 方法中返回一个包含 mail 的键

return [
    'mail' => 'hello@percipio.london',
];

如果通知支持作为电子邮件发送,您应该在通知类中定义一个 toMail 方法。此方法将接收一个包含您在 via 方法中定义的一切的 $notifiable 对象。

toMail 函数应该返回一个 craft\mail\Message 实例。如果您希望发送多封电子邮件,也可以返回一个 craft\mail\Message 实例数组。让我们看看一个示例 toMail 方法

public function toMail($notifiable)
{
    $title = $this->event->sender->title;

    $message = new Message();
    $message->setTo($notifiable);
    $message->setSubject("A new blogpost was added");
    $message->setHtmlBody("
        <p>Hey there!</p>
        <p>A new blogpost was added with the title {$title}</p>
    ");

    return $message;
}

Slack通知

您需要为您的工作团队配置一个 "Incoming Webhook" 集成。此集成将为您提供可以在定义您的 via 函数时使用的 URL。

return [
    'slack' => '<YOUR_WEBHOOK_URL>',
];

实现和文档主要基于 Laravel Notifications

格式化 Slack 通知

如果通知支持作为 Slack 消息发送,您应该在通知类中定义一个 toSlack 方法。此方法应该返回一个 percipioglobal\notifications\messages\SlackMessage 实例。Slack 消息可以包含文本内容以及一个 "附件",它格式化额外的文本或字段数组。让我们看看一个基本的 toSlack 示例

/**
 * Get the Slack representation of the notification.
 *
 * @param  mixed  $notifiable
 * @return SlackMessage
 */
public function toSlack()
{
    return (new SlackMessage)
          ->content('A new blogpost was added!');
}

自定义发件人和收件人

您可以使用 fromto 方法来自定义发件人和收件人。from 方法接受用户名和表情标识符,而 to 方法接受频道或用户名

/**
 * Get the Slack representation of the notification.
 *
 * @param  mixed  $notifiable
 * @return SlackMessage
 */
public function toSlack($notifiable)
{
    return (new SlackMessage)
        ->from('Ghost', ':ghost:')
        ->to('#other')
        ->content('This will be sent to #other');
}

您还可以使用图像作为您的徽标而不是表情

/**
 * Get the Slack representation of the notification.
 *
 * @param  mixed  $notifiable
 * @return SlackMessage
 */
public function toSlack($notifiable)
{
    return (new SlackMessage)
        ->from('Laravel')
        ->image('https://yoursite.com/favicon.png')
        ->content('This will display your logo next to the message');
}

Slack附件

您还可以在 Slack 消息中添加 "附件"。附件比简单的文本消息提供了更丰富的格式化选项。在这个例子中,我们将发送一个关于应用程序中发生的异常的错误通知,包括查看异常详细信息链接

/**
 * Get the Slack representation of the notification.
 *
 * @param  mixed  $notifiable
 * @return SlackMessage
 */
public function toSlack($notifiable)
{
    $url = url('/exceptions/'.$this->exception->id);

    return (new SlackMessage)
        ->error()
        ->content('Whoops! Something went wrong.')
        ->attachment(function ($attachment) use ($url) {
            $attachment->title('Exception: File Not Found', $url)
                       ->content('File [background.jpg] was not found.');
        });
}

上面的示例将生成如下所示的 Slack 消息:Basic Slack attachment

附件还允许您指定应向用户展示的数据数组。给定数据将以表格格式呈现,便于阅读。

/**
 * Get the Slack representation of the notification.
 *
 * @param  mixed  $notifiable
 * @return SlackMessage
 */
public function toSlack($notifiable)
{
    $url = url('/invoices/'.$this->invoice->id);

    return (new SlackMessage)
        ->success()
        ->content('One of your invoices has been paid!')
        ->attachment(function ($attachment) use ($url) {
            $attachment->title('Invoice 1322', $url)
                       ->fields([
                            'Title' => 'Server Expenses',
                            'Amount' => '$1,234',
                            'Via' => 'American Express',
                            'Was Overdue' => ':-1:',
                        ]);
        });
}

上面的示例将生成如下所示的 Slack 消息:基本 Slack 附件

Markdown 附件内容

如果您的某些附件字段包含 Markdown,您可以使用 markdown 方法指导 Slack 解析并显示给定附件字段为 Markdown 格式的文本。此方法接受的值有:pretexttext 以及 / 或 fields。有关 Slack 附件格式的更多信息,请参阅 Slack API 文档

/**
 * Get the Slack representation of the notification.
 *
 * @param  mixed  $notifiable
 * @return SlackMessage
 */
public function toSlack($notifiable)
{
    $url = url('/exceptions/'.$this->exception->id);

    return (new SlackMessage)
        ->error()
        ->content('Whoops! Something went wrong.')
        ->attachment(function ($attachment) use ($url) {
            $attachment->title('Exception: File Not Found', $url)
                       ->content('File [background.jpg] was *not found*.')
                       ->markdown(['text']);
        });
}

通知事件

当发送通知时,会触发两个事件,分别是 NotificationsService::EVENT_BEFORE_SENDNotificationsService::EVENT_AFTER_SEND,这两个事件会发送一个 percipioglobal\notifications\events\SendEvent 事件。

sendEvent 包含以下属性:

/**
 * @var mixed The notifiable.
 */
public $notifiable;
 
/**
 * @var NotificationsRecord The notification about to be sent.
 */
public $notification;
 
/**
 * @var string The channel on which the notification is about to be sent.
 */
public $channel;
 
/**
 * @var bool Whether we send the notification
 */
public $sendNotification = true;
 
/**
 * @var mixed The response after sending the event
 */
public $response = null;

当监听 EVENT_BEFORE_SEND 时,可以修改 sendNotification 属性以阻止发送通知。仅当 EVENT_AFTER_SEND 事件发生时,才会设置 response 属性。

自定义频道

Craft Notifications 随附了三个渠道(数据库、邮件和 Slack),但您可能希望编写自己的驱动程序,通过其他渠道发送通知。我们通过公开一个可以注册新渠道的事件来简化这个过程。

让我们来看看如何注册一个 voice 渠道。

Event::on(
    NotificationsService::class,
    NotificationsService::EVENT_REGISTER_CHANNELS,
    function (RegisterChannelsEvent $event) {
        $event->channels[] = [
            'voice' => function () {
                return new VoiceChannel();
            },
        ];
    }
);

您的 VoiceChannel 类将如下所示:

<?php

namespace app\channels;

use percipioglobal\notifications\models\Notification;

class VoiceChannel
{
    /**
     * Send the given notification.
     *
     * @param  mixed  $notifiable
     * @param  \percipioglobal\notifications\models\Notification  $notification
     * @return void
     */
    public function send($notifiable, Notification $notification)
    {
        $message = $notification->toVoice($notifiable);

        // Send notification to the $notifiable...
    }
}

一旦定义了您的通知渠道类,您只需将键添加到您的通知中的 via 方法即可。值应该是什么取决于您渠道的实现。

<?php

namespace App\Notifications;

use app\channels\VoiceChannel;
use app\channels\messages\VoiceMessage;
use percipioglobal\notifications\models\Notification;

class InvoicePaid extends Notification
{
    /**
     * Get the notification channels.
     *
     * @param  mixed  $notifiable
     * @return array|string
     */
    public function via($notifiable)
    {
        return [
            'voice' => '<YOUR_DESTINATION>',
        ];
    }

    /**
     * Get the voice representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return VoiceMessage
     */
    public function toVoice($notifiable)
    {
        // ...
    }
}

渠道的实现与 Laravel 的实现非常相似,如果您需要特定的渠道,您有很大机会在 Laravel 通知渠道 上找到它,只需进行一些实现上的更改。

添加渠道的功能可以非常容易地提取为插件,如果您实现了自定义插件,请考虑与社区分享。

Percipio Global Ltd. 提供。