snebes/notifications

v1.0.1 2019-09-18 04:41 UTC

This package is auto-updated.

Last update: 2024-09-18 15:39:29 UTC


README

GitHub release GitHub license Scrutinizer build Scrutinizer coverage Scrutinizer code quality PHP

snebes/notifications 是一个抽象层,灵感来源于 Laravel,允许您轻松地添加对电子邮件和Web界面消息的支持。

先决条件

此包使用 Symfony 3.4+ 组件以及 SwiftMailer 来提供通知。

安装

snebes/notifications 添加到您的 composer.json 文件中

composer require snebes/notifications

如果您想在基于 Symfony 3.4+ 的应用程序中使用此组件,则可以安装 snebes/notifications-bundle 来简化此配置。 查看包文档。

设置/引导

通知组件基于 Symfony 的 Event Dispatcher 构建,这是在 PHP 生态系统中常用的。

use Symfony\Component\EventDispatcher\EventDispatcher;

$eventDispatcher = new EventDispatcher();
$notificationSender = new NotificationSender($eventDispatcher);

通知渠道

注册数据库渠道以利用Web界面通知。此组件中包含的数据库渠道依赖于 Doctrine。

$databaseChannel = new DatabaseChannel($doctrineEntityManager);
$eventDispatcher->addListener(NotificationEvents::SEND, [$databaseChannel, 'send']);

注册邮件渠道以利用电子邮件通知。此组件中包含的邮件渠道依赖于 SwiftMailer。

$transport = new Swift_SmtpTransport('smtp.example.org', 25);
$mailer = new SwiftMailerMailer(new Swift_Mailer($transport));

$mailChannel = new MailChannel($mailer);
$eventDispatcher->addListener(NotificationEvents::SEND, [$mailChannel, 'send']);

发送通知

可以通过 NotificationSender 服务发送通知。

<?php

namespace App\Service;

use App\Entity\User;
use App\Notifications\OrderNotification;
use SN\Notifications\NotificationSender;

class UserService
{
    private $notificationSender;

    public function __construct(NotificationSender $notificationSender)
    {
        $this->notificationSender = $notificationSender;    
    }

    public function send(User $user)
    {
        $this->notificationSender->send($user, new OrderNotification());
    }
}

此组件提供帮助程序,使类,如上面的 User 类,可以接受通知。 NotifiableTrait 为任何类添加接收数据库或邮件消息的能力。

要从实体引用数据库通知,需要为 Doctrine 配置 $notification 字段以映射关系。

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use SN\Bundle\NotificationsBundle\Entity\Notification;
use SN\Notifications\Contracts\NotifiableInterface;
use SN\Notifications\NotifiableTrait;

/**
 * @ORM\Entity()
 */
class User implements NotifiableInterface
{
    use NotifiableTrait;

    /**
     * This field is used by the Mail channel.
     * 
     * @var string
     */
    private $email = 'demo@example.com';

    /**
     * This field is used by the SMS channel.
     * 
     * @var string
     */
    private $phoneNumber = '+1 555 555 5555';

    /**
     * @var Notification[]
     *
     * @ORM\ManyToMany(targetEntity=Notification::class)
     * @ORM\JoinTable(name="user_notifications")
    */
    private $notifications;
}

指定投递渠道

每个通知类都有一个 via 方法,它确定通知将在哪些渠道上投递。通知可以在 maildatabase 渠道上发送。

via 方法接收一个 NotifiableInterface 实例,该实例将是接收通知的类的实例。您可以使用 NotifiableInterface 来确定通知应该通过哪些渠道发送。

/**
 * Get the notification's delivery channels.
 *
 * @param NotifiableInterface $notifiable
 *
 * @return array
 */
public function via(NotifiableInterface $notifiable): array
{
    return $notifiable->doNotSendEmail() ? ['database'] : ['database', 'mail'];
}

邮件通知

如果通知支持作为电子邮件发送,则类应实现 MailableInterface 并定义一个 toMail 方法。此方法将接收一个 NotifiableInterface 实体,并应返回一个 SN\Notifications\Contracts\EmailInterface; 实例。让我们看看一个 toMail 方法的例子

<?php

namespace App\Notification;

use SN\Notifications\Contracts\EmailInterface;
use SN\Notifications\Contracts\MailableInterface;
use SN\Notifications\Contracts\NotifiableInterface;
use SN\Notifications\Contracts\NotificationInterface;
use SN\Notifications\Email\Address;
use SN\Notifications\Email\Email;

class OrderNotification implements NotificationInterface, MailableInterface
{
    /**
     * Get the notification's delivery channels.
     *
     * @param NotifiableInterface $notifiable
     *
     * @return array
     */
    public function via(NotifiableInterface $notifiable): array
    {
        return ['mail'];
    }

    /**
     * Get the mail representation of the notification.
     *
     * @param NotifiableInterface $notifiable
     *
     * @return EmailInterface
     */
    public function toMail(NotifiableInterface $notifiable): EmailInterface
    {
        return (new Email())
            ->from(new Address('orders@example.com'))
            ->subject('Thank you for your order.')
            ->text('We are processing your order right now!');
    }
}

在这个例子中,我们创建了一个带有主题和文本行的电子邮件。这些由 Email 对象提供的方法使格式化小型交易性电子邮件变得简单快捷。邮件渠道将自动为每个 NotifiableInterface 填充 to 地址。

自定义收件人

在通过 mail 渠道发送通知时,通知系统将自动在您的 NotifiableInterface 实体上查找 email 属性。您可以通过在实体上定义 routeNotificationForMail 方法来自定义用于发送通知的电子邮件地址。

<?php

namespace App\Entity;

use SN\Notifications\Contracts\NotifiableInterface;
use SN\Notifications\Contracts\NotificationInterface;use SN\Notifications\NotifiableTrait;

class User implements NotifiableInterface
{
    use NotifiableTrait;

    /**
     * Route notifications for the mail channel.
     *
     * @param NotificationInterface $notification
     *
     * @return string
     */
    public function routeNotificationForMail(NotificationInterface $notification)
    {
        return $this->getEmailAddress();
    }
}

数据库通知

先决条件

数据库通知渠道将通知信息存储在数据库表中。该表将包含诸如通知类型以及描述通知的定制 JSON 数据等信息。

您可以在应用程序的用户界面中查询表以显示通知。但在进行之前,您需要创建一个数据库表来存储您的通知。根据您应用程序的配置,您需要创建具有以下模式的表

CREATE TABLE `sn_notification` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `created_at` datetime NOT NULL,
  `notifiable_id` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL,
  `notifiable_type` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `read_at` datetime DEFAULT NULL,
  `data` json DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `notifiable_idx` (`notifiable_id`,`notifiable_type`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

数据库通知格式化

如果通知支持存储在数据库表中,则类应该实现 ArrayableInterface 并定义一个 toArray 方法。此方法将接收一个 NotifiableInterface 实体,并应返回一个纯PHP数组。返回的数组将作为JSON编码并存储在通知表的data列中。让我们看看一个示例 toArray 方法

<?php

namespace App\Notification;

use SN\Notifications\Contracts\ArrayableInterface;
use SN\Notifications\Contracts\NotifiableInterface;
use SN\Notifications\Contracts\NotificationInterface;

class OrderNotification implements NotificationInterface, ArrayableInterface
{
    /**
     * Get the notification's delivery channels.
     *
     * @param NotifiableInterface $notifiable
     *
     * @return array
     */
    public function via(NotifiableInterface $notifiable): array
    {
        return ['mail'];
    }

    /**
     * Get the mail representation of the notification.
     *
     * @param NotifiableInterface $notifiable
     *
     * @return array
     */
    public function toArray(NotifiableInterface $notifiable): array
    {
        return [
            'order_id' => $this->orderId,
            'amount'   => $this->amount,
        ];
    }
}

访问通知

一旦通知存储在数据库中,您需要一种方便的方法从您的可通知实体中访问它们。此组件包含的 NotifiableTrait 提供了对 $notifications 关系的助手,该关系返回实体的通知。要获取通知,您可以使用 getNotifications()getUnreadNotifations()getReadNotifications() 方法。默认情况下,通知将按 createdAt 时间戳排序

$user = $this->getUser();

foreach ($user->getUnreadNotifications() as $notification) {
    echo $notification->data['message'];
}

标记通知为已读

通常,当用户查看通知时,您会想将其标记为“已读”。SSN\Bundle\NotificationsBundle\Entity\Notification 实体类提供了一个 setReadAt 方法,该方法更新通知数据库记录中的 readAt

$user = $this->getUser();

foreach ($user->getUnreadNotifications() as $notification) {
    $notification->setReadAt(new \DateTime());
}

通知事件

当发送通知时,组件会触发多个事件,您可以使用这些事件来修改通知的处理方式。

NotificationEvents::SENDING

事件类: SN\Notifications\Event\NotificationSendingEvent

此事件在发送通知之前触发。它很有用,可以向通知添加更多信息或阻止通知发送。

执行此命令以找出注册为此事件的监听器及其优先级

bin/console debug:event-dispatcher sn.notifications.sending

NotificationEvents::SEND

事件类: SN\Notifications\Event\NotificationSendEvent

此事件用于发送通知。其主要用途是将通知发送到所需的频道,这是在此组件内部使用频道的方式。

执行此命令以找出注册为此事件的监听器及其优先级

bin/console debug:event-dispatcher sn.notifications.send

NotificationEvents::SENT

事件类: SN\Notifications\Event\NotificationSentEvent

此事件在成功发送通知后触发。它很有用,可以对已发送的通知执行任务。

执行此命令以找出注册为此事件的监听器及其优先级

bin/console debug:event-dispatcher sn.notifications.sent

NotificationEvents::EXCEPTION

事件类: SN\Notifications\Event\NotificationExceptionEvent

此事件在处理通知时发生错误时触发。它很有用,可以从中恢复或修改通知。

执行此命令以找出注册为此事件的监听器及其优先级

bin/console debug:event-dispatcher sn.notifications.exception

自定义频道

此组件提供了一些通知频道,但您可能想编写自己的频道以通过其他方法发送通知。派发的通知事件使其变得简单。要开始,定义一个类,该类侦听或订阅 NotificationEvents::SEND 事件。

<?php

namespace App\Channel;

use SN\Notifications\Event\NotificationSendEvent;
use SN\Notifications\NotificationEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class CustomChannel implements EventSubscriberInterface
{
    /**
     * @return array
     */
    public static function getSubscribedEvents(): array
    {
        return [
            NotificationEvents::SEND => 'send',
        ];
    }

    /**
     * Send the given notification.
     *
     * @param NotificationSendEvent $event
     */
    public function send(NotificationSendEvent $event): void
    {
        $notifiable = $event->getNotifiable();
        $notification = $event->getNotification();

        // Send notification to the $notifiable.
    }
}

一旦定义了您的通知频道类,您就可以从任何通知的 via 方法中返回类名。