dvamigos/yii2-notifications

Yii 2+ 的通知系统

1.1.3 2018-10-25 15:43 UTC

This package is not auto-updated.

Last update: 2024-09-29 09:52:38 UTC


README

Yii 2+ 的通知系统

使用方法

默认存储为您的数据库。为此,您需要从 src/migrations 文件夹中插入迁移。

要插入这些迁移,您需要运行迁移命令

yii migrate --migrationPath=@vendor/dvamigos/yii2-notifications/src/migrations

这将创建数据库中的 notification 表。如果您不打算在数据库中存储通知,则此步骤不是必需的。

在您的应用程序配置中添加通知组件配置

[
    'components' => [
        'notifications' => [
            'class' => '\dvamigos\Yii2\Notifications\NotificationManager',
            'types' => [
                'text' => [
                     'my_notification' => 'This is my notification'
                ]
            ]
        ]
    ]
]

然后在您的代码中,您可以直接使用以下方式发送通知

Yii::$app->notifications->push('my_notification');

这将保存当前登录用户的通知。

通知类型

您可以为您的通知定义任意数量的类型,以便存储所需的数据。

以下是一个具有 titlemessage 的示例通知。

[
    'components' => [
        'notifications' => [
            'class' => '\dvamigos\Yii2\Notifications\NotificationManager',
            'types' => [
                'new_user' => [
                    'text' => [
                        'title' => 'New user created!',
                        'message' => 'New user {username} is created.'
                    ],
                    'default' => [
                        'username' => ''
                    ]
                ]
            ]
        ]
    ]
]

字段 {username} 将在创建通知时从传递给通知的数据中替换。

要传递数据,只需使用以下方式

Yii::$app->notifications->push('new_user', [
    'username' => 'JohnDoe94'
]);

您不必始终将所有必要的键传递到数据中。如果您不传递所需的键,则其值将从该通知的 'default' 中获取。

您还可以使用此数组传递任何可以序列化为 JSON 字符串的任意信息,从而有效地存储显示或使用通知所需的任何所需数据。

在模型/控制器/组件中使用

您可以在具有 events() 函数的每个组件中使用 PushNotificationUpdateNotificationReplaceNotification 类。

要包含 events() 函数,请使用 EventListAwareTrait

例如,要在模型中设置它,可以定义以下内容

public function events()
{
    self::EVENT_AFTER_INSERT => [
        new \dvamigos\Yii2\Notifications\events\PushNotification([
            'type' => 'my_notification',
            'data' => ['my_data' => 1]
        ])
    ]
}

类型可以在之后解决

public function events()
{
    self::EVENT_AFTER_INSERT => [
        new \dvamigos\Yii2\Notifications\events\PushNotification([
            'type' => function(PushNotification $n) {
                return 'my_type';
            },
            'data' => function(PushNotification $n) {
                return ['my_key' => $this->getPrimaryKey()];
            }
        ])
    ]
}

如果您希望使用行为方法,这也可以通过 NotificationBehavior 类实现。

要使用该类,您可以在支持行为的模型/组件中简单添加

public function behaviors() 
{
    return [
        'notification' => [
            'class' => \dvamigos\Yii2\Notifications\events\NotificationBehavior::class,
            'events' => [
                self::EVENT_AFTER_INSERT => [
                    [
                       'class' => \dvamigos\Yii2\Notifications\events\PushNotification,
                       'type' => function(PushNotification $n) {
                            return 'my_type';
                        },
                        'data' => function(PushNotification $n) {
                            return ['my_key' => $this->getPrimaryKey()];
                        }
                    ]
                ]
            ]
        ]
    ];
}

如果您想封装自己的逻辑,那么通过扩展 \dvamigos\Yii2\Notifications\events\PushNotification 来创建自己的类也是可能的。

示例

class MyNotification extends \dvamigos\Yii2\Notifications\events\PushNotification {
    public $type = 'my_notification_type';
    
    public function init() {
        $this->data = [$this, 'handleMyData'];
        parent::init();
    }
    
    public function handleMyData(MyNotification $instance, \yii\base\Event $event)
    {
        // You logic for returning data here...
    }
}
public function behaviors() 
{
    return [
        'notification' => [
            'class' => \dvamigos\Yii2\Notifications\events\NotificationBehavior::class,
            'events' => [
                self::EVENT_AFTER_INSERT => [
                    MyNotification::class
                ]
            ]
        ]
    ];
}

然后您可以简单地添加以下通知

多个目标

在发送通知时,您可以定义多个目标,从而有效地同时向手机设备、数据库等推送通知。

您的默认目标是数据库,但您可以使用以下方式定义自己的目标

[
    'components' => [
        'notifications' => [
            'class' => '\dvamigos\Yii2\Notifications\NotificationManager',
            'activeTarget' => ['database', 'android', 'ios'],
            'targets' => [
                'database' => [
                    'class' => '\dvamigos\Yii2\Notifications\targets\DatabaseTarget',
                    // ... config
                ],
                'android' => [
                    'class' => '\dvamigos\Yii2\Notifications\targets\AndroidFcmTarget',
                    'apiKey' => 'YOUR API KEY',
                    'tokenRetriever' => function(NotificationInterface $n) {
                        return $n->getData()['fcmToken'];
                    }
                ],
                'ios' => [
                    'class' => '\dvamigos\Yii2\Notifications\targets\IosApnTarget',
                    'pemFile' => '@app/path/to/your/pem/file.pem',
                    'password' => 'yourpassphrase',
                    'tokenRetriever' => function(NotificationInterface $n) {
                        return $n->getData()['iosToken'];
                    }
                ]
            ],
            'types' => [
                'new_user' => [
                    'text' => [
                        'title' => 'New user created!',
                        'message' => 'New user {username} is created.'
                    ],
                    'default' => [
                        'username' => '',
                        'fullName' => 'Unknown',
                        'gender' => 'male'
                    ]
                ]
            ]
        ]
    ]
]

注意

请注意,Android 和 iOS 目标是 WIP 且未完全测试,可能无法正常工作。

使用上述配置,当调用以下内容时

Yii::$app->notifications->push('new_user', [
    'username' => 'JohnDoe94',
    'fcmToken' => "Your user's android notification token",
    'iosToken' => "Your user's ios notification token"
]);

您将向数据库、您的用户的 Android 设备和 iOS 设备发送通知。

您可以在任何时间切换目标

Yii::$app->notification->pushTarget('database'); // Will only send to database.
    Yii::$app->notification->pushTarget('android'); // Will only send to android.
        Yii::$app->notification->pushTarget(['android', 'ios']); // Will only send to android and ios targets.
            // Send notification to android/ios
        Yii::$app->notification->popTarget(); // restores previous target - 'android'
        // Send notification to android
    Yii::$app->notification->popTarget(); // restores previous target - 'database'
    // Send notification to database
Yii::$app->notification->popTarget(); // restores previous target - as defined in initial configuration.

请注意,您应该使用 popTarget() 来恢复旧的行为。例如

Yii::$app->notification->pushTarget(['android', 'ios']); // Will only send to android and ios targets.
// send notification
Yii::$app->notification->popTarget(); // restores previous active target.

您可以使用以下方式调用特定的目标

Yii::$app->notification->getTarget('database'); // Returns DatabaseTarget

或者您可以使用 forTargets() 在特定目标上执行命令

Yii::$app->notification->forTargets(['ios', 'android'], function(NotificationManager $manager) {
       $manager->push('notification'); // Will only push notification to ios, android
]);

令牌检索

由于某些目标在发送通知时需要额外的令牌数据,因此您可以根据每个目标需要哪些令牌来实现自己的令牌检索逻辑。

令牌检索器可以是一个 callable 闭包

[
    'components' => [
        'notifications' => [
            'class' => '\dvamigos\Yii2\Notifications\NotificationManager',
            'activeTarget' => ['database', 'android', 'ios'],
            'targets' => [
                'android' => [
                    'class' => '\dvamigos\Yii2\Notifications\targets\AndroidFcmTarget',
                    'apiKey' => 'YOUR API KEY',
                    'tokenRetriever' => function(NotificationInterface $n) {
                        return $n->getData()['fcmToken'];
                    }
                ]
            ],
        ]
]

tokenRetriever 可调用将在每次发送通知时需要令牌时调用。

tokenRetriever 也可以是一个实现了 dvamigos\Yii2\Notifications\TokenRetrievalInterface 的类。

class MyTokenRetrieval extends BaseObject implements dvamigos\Yii2\Notifications\TokenRetrievalInterface {
    public $target;
    
    protected $cachedTokens = [];
    
     // This example assumes you have UserTokens ActiveRecord
     // which has columns: user_id, type, token
     // And that will be used to retrieve user's token.
    public function getToken(NotificationInterface $n) {
    
         // This will cache tokens so that you dont need to
         // hit database for every notification.
         
         if (!empty($this->cachedTokens[$n->getUserId()])) {
              return $this->cachedTokens[$n->getUserId()];
         }
        
         // Returns and caches token.
         return $this->cachedTokens[$n->getUserId()] = UserTokens::find()
            ->where([
                'user_id' => $n->getId(),
                'type' => $this->target
            ])
            ->select('token')
            ->scalar() ?: '';
    }

}

配置

[
    'components' => [
        'notifications' => [
            'class' => '\dvamigos\Yii2\Notifications\NotificationManager',
            'activeTarget' => ['database', 'android', 'ios'],
            'targets' => [
                'android' => [
                    'class' => '\dvamigos\Yii2\Notifications\targets\AndroidFcmTarget',
                    'apiKey' => 'YOUR API KEY',
                    'tokenRetriever' => [
                        'class' => MyTokenRetrieval::class,
                        'target' => 'android' 
                    ]
                ],
                'ios' => [
                    'class' => '\dvamigos\Yii2\Notifications\targets\IosApnTarget',
                    'pemFile' => '@app/path/to/your/pem/file.pem',
                    'password' => 'yourpassphrase',
                    'tokenRetriever' => [
                        'class' => MyTokenRetrieval::class,
                        'target' => 'ios' 
                    ]
                ]
            ],
        ]
]

显示通知

您可以使用 NotificationList 小部件来显示您的通知。

请注意,根据您的使用情况,您需要配置此小部件以满足您的需求。此小部件假定您的组件名称为 notification,尽管您可以在小部件创建期间传递不同的名称。

您需要使用此小部件指定通知的模板。

以下是一个简单列表的示例,其中通知被定义为。

[
    'components' => [
        'notifications' => [
            'class' => '\dvamigos\Yii2\Notifications\NotificationManager',
            'types' => [
                'new_user' => [
                    'text' => [
                        'title' => 'New user created!',
                        'message' => 'New user {username} is created.'
                    ],
                    'default' => [
                        'username' => '',
                        'fullName' => 'Unknown',
                        'gender' => 'male'
                    ]
                ]
            ]
        ]
    ]
]
<?= \dvamigos\Yii2\Notifications\widgets\NotificationList::widget([
    'containerTemplate' => '<ul>{notifications}{emptyText}</ul>',
    'emptyText' => '<li>No notifications available.</li>',
    'itemTemplate' => '
        <li>
            <span class="title">{text.title}</span>
            <span class="message">{text.message}</span>
            <span class="at">{timestamp}</span>
        </li>
    '
]); ?>

也支持自定义部分。您可以定义它们为

<?= \dvamigos\Yii2\Notifications\widgets\NotificationList::widget([
    'containerTemplate' => '<ul>{notifications}{emptyText}</ul>',
    'emptyText' => '<li>No notifications available.</li>',
    'itemTemplate' => '
        <li>
            <span class="title">{text.title}</span>
            <span class="message">{text.message}</span>
            <span class="message">User full name: {section.fullName}</span>
        </li>
    ',
    'sections' => [
        'fullName' => function($context) {
            /** @var \dvamigos\Yii2\Notifications\NotificationInterface $n */
            $n = $context['notification'];
            
            if ($n->getType() !== 'new_user') {
                return '';
            }
            
            return $n->getData()['fullName'];
        }
    ]
]); ?>

请参考代码中的 NotificationList 文档以获取有关可用信息的更多信息。

最佳实践是扩展此 NotificationList 小部件以适应您自己的,并根据您自己的项目需求实现此功能。