mayocube / craft-notifications
通过多种渠道发送通知,包括邮件和Slack。通知也可以存储在数据库中,以便在您的网页界面中显示。
Requires
- php: ^8.2
- craftcms/cms: ^5.0.0
- guzzlehttp/guzzle: ^7.0
- nesbot/carbon: ^2.19
Requires (Dev)
- craftcms/phpstan: dev-main
- craftcms/rector: dev-main
README
Craft CMS 5.x 的通知插件
通过多种渠道发送通知,包括邮件和Slack。通知也可以存储在数据库中,以便在您的网页界面中显示。
支持开源。买啤酒。
此插件根据MIT许可证授权,这意味着它是完全免费的开放源代码软件,您可以使用它来做什么和如何使用。如果您在使用它并希望支持开发,请在Beerpay上为我买一杯啤酒!
要求
此插件需要Craft CMS 5.0.0或更高版本。
安装
要安装插件,请按照以下说明操作。
-
打开您的终端并转到您的Craft项目
cd /path/to/project -
然后告诉Composer加载插件
composer require mayocube/craft-notifications -
在控制面板中,转到设置→插件,并单击“安装”按钮安装通知。
-
将
config.php文件复制到您的应用程序中的config/notifications.php。 -
通过向您的
composer.json添加以下内容并运行composer dump -o来确保您的通知被自动加载。
"autoload": {
"psr-4": {
"app\\notifications\\": "./notifications"
}
},
简介
通常,通知应该是简短的信息性消息,通知用户您的应用程序中发生的事情。例如,如果您正在编写账单应用程序,您可能通过电子邮件和短信渠道向用户发送“发票已支付”的通知。
创建通知
每个通知由一个单独的类表示(存储在您的应用程序的 notifications 目录中)。您必须手动创建它,或者当您运行 notifications/make 命令时,它会为您创建。
./craft notifications/make BlogPostAdded
此命令将在您的 notifications 目录中放置一个新的通知类。每个通知类都包含一个 via 方法以及一系列用于构建消息的方法(例如 toMail 或 toDatabase),这些方法将通知转换为针对特定渠道优化的消息。
发送通知
通知可以通过两种方式发送,一种是从配置文件,在 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,它包含 sender 和 isNew 属性,使用这些信息我们可以确定只有当条目来自 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 类应该定义一个 toDatabase 或 toArray 函数。
这可以非常简单,例如
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!'); }
自定义发件人和收件人
您可以使用 from 和 to 方法来自定义发件人和收件人。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.'); }); }
附件还允许您指定应向用户展示的数据数组。给定数据将以表格格式呈现,便于阅读。
/** * 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:', ]); }); }
Markdown 附件内容
如果您的某些附件字段包含 Markdown,您可以使用 markdown 方法指导 Slack 解析并显示给定附件字段为 Markdown 格式的文本。此方法接受的值有:pretext、text 以及 / 或 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_SEND 和 NotificationsService::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. 提供。
