Yii2 消息逻辑Message
通知模块
1.组件方式实现
目录结构化建议
common/
├── components/
│ └── notify/
│ ├── NotifyManager.php
│ ├── NotifyStrategyInterface.php
│ └── strategies/
│ ├── WechatStrategy.php
│ └── SmsStrategy.php
├── jobs/
│ └── NotifyJob.php
├── services/
│ └── RemindService.php
console/
├── controllers/
│ └── RemindController.php
config/
├── main.php
├── main-local.php
1. 通知接口NotifyStrategyInterface.php
namespace common\components\notify;
interface NotifyStrategyInterface
{
public function send($userId, string $title, string $message): bool;
}
2. 示例通道: 微信策略WechatStrategy.php
namespace common\components\notify\strategies;
use common\components\notify\NotifyStrategyInterface;
use Yii;
class WechatStrategy implements NotifyStrategyInterface
{
public function send($userId, string $title, string $message): bool
{
Yii::info("【微信通知】发送给用户{$userId}:{$title} - {$message}");
// 模拟微信 API 请求...
return true;
}
}
3. 多通道管理NotifyManager
namespace common\components\notify;
use Yii;
use yii\base\Component;
class NotifyManager extends Component
{
private $strategies = [];
// 如果使用了工厂模式可以考虑使用该方法来处理
// public function init()
// {
// parent::init();
// $all = NotifyChannelFactory::buildAll();
// foreach ($all as $channel => $strategy) {
// $this->register($channel, $strategy);
// }
// }
public function register(string $name, NotifyStrategyInterface $strategy): void
{
$this->strategies[$name] = $strategy;
}
public function send(array $channels, $userId, string $title, string $message): void
{
foreach ($channels as $channel) {
if (isset($this->strategies[$channel])) {
$this->strategies[$channel]->send($userId, $title, $message);
} else {
Yii::warning("未注册的通知通道:{$channel}");
}
}
}
}
4.组件注册(common/config/main.php)
'components' => [
'notifyManager' => [
'class' => 'common\components\notify\NotifyManager',
],
'queue' => [
'class' => \yii\queue\db\Queue::class,
'db' => 'db',
'tableName' => '{{%queue}}',
'channel' => 'default',
'mutex' => \yii\mutex\MysqlMutex::class,
],
],
5. 通道注册(bootstrap)
# 在 common/config/bootstrap.php 添加:
use Yii;
use common\components\notify\strategies\WechatStrategy;
Yii::$app->notifyManager->register('wechat', new WechatStrategy());
6. 异步任务类
namespace common\jobs;
use yii\base\BaseObject;
use yii\queue\JobInterface;
class NotifyJob extends BaseObject implements JobInterface
{
public $userId;
public $title;
public $message;
public $channels = [];
public function execute($queue)
{
\Yii::$app->notifyManager->send($this->channels, $this->userId, $this->title, $this->message);
}
}
7. 核心业务逻辑RemindService
namespace common\services;
use Yii;
use common\jobs\NotifyJob;
use common\models\Child;
class RemindService
{
public function run()
{
$daysList = [7, 14, 30, 60, 120, 180, 365];
foreach ($daysList as $day) {
$targetDate = date('Y-m-d', strtotime("-{$day} days +2 days"));
$children = Child::find()->where(['birth_date' => $targetDate])->all();
foreach ($children as $child) {
Yii::$app->queue->push(new NotifyJob([
'userId' => $child->parent_id,
'title' => '疫苗提醒',
'message' => "{$child->name} 出生第{$day}天,请安排接种",
'channels' => ['wechat'],
]));
}
}
}
}
8. Console定时命令RemindController.php
namespace console\controllers;
use yii\console\Controller;
use common\services\RemindService;
class RemindController extends Controller
{
public function actionRun()
{
$service = new RemindService();
$service->run();
echo "疫苗提醒任务完成\n";
}
}
9. 配置定时任务(crontab)
# 每天10点提醒任务
0 10 * * * /usr/bin/php /your-project/yii remind/run >> /var/log/remind.log 2>&1
10. 添加自动扫描+工厂注册的NotifyManager.(可选)
namespace common\components\notify;
use Yii;
use yii\helpers\FileHelper;
use yii\helpers\StringHelper;
class NotifyChannelFactory
{
public static function buildAll(): array
{
$baseNamespace = 'common\\components\\notify\\strategies';
$basePath = Yii::getAlias('@common/components/notify/strategies');
$strategies = [];
foreach (FileHelper::findFiles($basePath, ['only' => ['*.php']]) as $file) {
$className = $baseNamespace . '\\' . basename($file, '.php');
if (class_exists($className)) {
$instance = new $className();
if ($instance instanceof NotifyStrategyInterface) {
// 以类名中的 "WechatStrategy" -> "wechat" 作为通道名
$shortName = (new \ReflectionClass($className))->getShortName();
$channel = strtolower(str_replace('Strategy', '', $shortName));
$strategies[$channel] = $instance;
}
}
}
return $strategies;
}
}
2.依赖注入实现
| 依赖注入+多通道 + 定时任务 + 队列可扩展性
目录结构化建议
common/
├── components/
│ └── SmsComponent.php # 封装短信逻辑
├── services/
│ ├── NotifyInterface.php # 通知接口
│ ├── SmsNotifyService.php # 实现类:短信
│ ├── MultiNotifyService.php # 实现类:多通道组合
│ └── RemindService.php # 核心业务逻辑服务
├──console/
| └──controllers/
│ └──RemindController.php # 控制台命令
├── config/
| └──main.php # DI 配置绑定
1. 定义接口NotifyInterface.php
namespace common\services;
interface NotifyInterface
{
public function send($userId, string $title, string $message): bool;
}
2. 实现短信服务
namespace common\services;
use Yii;
class SmsNotifyService implements NotifyInterface
{
public function send($userId, string $title, string $message): bool
{
return Yii::$app->sms->send($userId, $message); // 假设你封装了 sms 组件
}
}
3. 多通道服务MultiNotifyService
namespace common\services;
class MultiNotifyService implements NotifyInterface
{
private array $channels;
public function __construct(array $channels)
{
$this->channels = $channels;
}
public function send($userId, string $title, string $message): bool
{
foreach ($this->channels as $channel) {
$channel->send($userId, $title, $message);
}
return true;
}
}
4. 核心业务逻辑RemindService.php
namespace common\services;
use common\models\Child;
use Yii;
class RemindService
{
private NotifyInterface $notifier;
public function __construct(NotifyInterface $notifier)
{
$this->notifier = $notifier;
}
public function process(): void
{
$remindDays = [7, 14, 30, 60, 120, 180, 365];
foreach ($remindDays as $day) {
$target = date('Y-m-d', strtotime("+{$day} days"));
$notifyDate = date('Y-m-d', strtotime($target . ' -2 days'));
$children = Child::find()->where(['birth_date' => $notifyDate])->all();
foreach ($children as $child) {
$this->notifier->send(
$child->parent_id,
"疫苗提醒",
"{$child->name} 将在出生 {$day} 天接种疫苗,请提前安排。"
);
}
}
}
}
5. Console命令RemindController
namespace console\controllers;
use Yii;
use yii\console\Controller;
use common\services\RemindService;
class RemindController extends Controller
{
public function actionRun()
{
/** @var RemindService $service */
$service = Yii::$container->get(RemindService::class);
$service->process();
echo "提醒任务执行完成。\n";
}
}
6. console/confi/main.php中添加依赖注入绑定
return [
'id' => 'app-console',
'basePath' => dirname(__DIR__),
'controllerNamespace' => 'console\controllers',
'bootstrap' => ['log'],
'components' => [
'log' => [...],
// 可选添加其他组件
],
'container' => [
'definitions' => [
NotifyInterface::class => SmsNotifyService::class,
RemindService::class => RemindService::class,
],
],
];