rias/craft-notifications

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

安装22,583

依赖: 2

建议者: 0

安全: 0

星标: 55

关注者: 6

分支: 8

类型:craft-plugin


README

icon

Craft CMS 3.x的通知插件

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

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

支持开源。买啤酒。

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

要求

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

安装

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

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

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

     composer require percipioglobal/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,
        ],
    ],
];

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

在我们的 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通知

您需要为您的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 Notification Channels 找到它,只需进行一些实现上的修改。

将添加通道的功能提取为插件是非常容易的,如果你实现了自定义插件,请考虑与社区分享。

Percipio Global Ltd. 提供