craftpulse/craft-notifications

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

安装: 299

依赖: 0

建议者: 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,
        ],
    ],
];

在这里,我们在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个月。如果您想自定义时间框架,请提供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方法接受一个用户名和emoji标识符,而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');
}

您也可以使用图像作为您的标志而不是emoji。

/**
 * 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. 提供