PHP 统一通知接口

wen PHP项目 4

我来为您设计一个PHP统一通知接口,这是一个常见的需求,用于接收来自不同渠道(短信、邮件、App推送等)的通知。

PHP 统一通知接口

统一通知接口设计方案

数据表结构

-- 通知数据表
CREATE TABLE `notifications` (
    `id` BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    `notification_id` VARCHAR(64) NOT NULL COMMENT '业务通知ID',
    `channel` VARCHAR(20) NOT NULL COMMENT '渠道: sms,email,push',
    `type` VARCHAR(50) NOT NULL COMMENT '通知类型', VARCHAR(200) DEFAULT NULL COMMENT '标题',
    `content` TEXT NOT NULL COMMENT '内容',
    `receiver` JSON NOT NULL COMMENT '接收者信息',
    `data` JSON DEFAULT NULL COMMENT '扩展数据',
    `status` TINYINT DEFAULT 0 COMMENT '状态: 0待发送,1已发送,2失败,3已读',
    `send_result` JSON DEFAULT NULL COMMENT '发送结果',
    `sent_at` DATETIME DEFAULT NULL COMMENT '发送时间',
    `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    INDEX `idx_notification_id` (`notification_id`),
    INDEX `idx_channel_status` (`channel`, `status`),
    INDEX `idx_created_at` (`created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

统一通知接口

<?php
/**
 * 统一通知接口
 * 
 * @author Your Name
 * @date 2024-01-01
 */
require_once 'database.php'; // 数据库连接
class UnifiedNotification {
    private $db;
    private $channels = [
        'sms' => 'SmsChannel',
        'email' => 'EmailChannel', 
        'push' => 'PushChannel',
        'wechat' => 'WechatChannel'
    ];
    public function __construct($db) {
        $this->db = $db;
    }
    /**
     * 统一发送通知接口
     * 
     * @param array $params 通知参数
     * @return array 发送结果
     */
    public function send($params) {
        try {
            // 参数验证
            $this->validateParams($params);
            // 构建通知数据
            $notification = [
                'notification_id' => $this->generateNotificationId(),
                'channel' => $params['channel'],
                'type' => $params['type'],
                'title' => $params['title'] ?? '',
                'content' => $params['content'],
                'receiver' => json_encode($params['receiver']),
                'data' => json_encode($params['data'] ?? []),
                'status' => 0
            ];
            // 保存到数据库
            $notificationId = $this->saveNotification($notification);
            // 发送通知
            $result = $this->dispatch($notification);
            // 更新发送状态
            $this->updateNotificationStatus($notificationId, $result);
            return [
                'code' => 200,
                'message' => '通知发送成功',
                'data' => [
                    'notification_id' => $notification['notification_id'],
                    'channel' => $params['channel'],
                    'status' => $result['status'],
                    'send_result' => $result
                ]
            ];
        } catch (Exception $e) {
            return [
                'code' => 400,
                'message' => $e->getMessage(),
                'data' => null
            ];
        }
    }
    /**
     * 批量发送通知
     */
    public function sendBatch($params) {
        $results = [];
        foreach ($params['notifications'] as $notification) {
            $results[] = $this->send($notification);
        }
        return [
            'code' => 200,
            'message' => '批量发送完成',
            'data' => $results
        ];
    }
    /**
     * 验证参数
     */
    private function validateParams($params) {
        // 必填参数检查
        $required = ['channel', 'type', 'content', 'receiver'];
        foreach ($required as $field) {
            if (empty($params[$field])) {
                throw new Exception("参数 {$field} 不能为空");
            }
        }
        // 渠道检查
        if (!isset($this->channels[$params['channel']])) {
            throw new Exception("不支持的渠道: {$params['channel']}");
        }
        // 接收者检查
        if (!is_array($params['receiver']) || empty($params['receiver'])) {
            throw new Exception("接收者信息不能为空");
        }
    }
    /**
     * 生成通知ID
     */
    private function generateNotificationId() {
        return date('YmdHis') . str_pad(mt_rand(1, 999999), 6, '0', STR_PAD_LEFT);
    }
    /**
     * 保存通知到数据库
     */
    private function saveNotification($data) {
        $sql = "INSERT INTO notifications (notification_id, channel, type, title, content, receiver, data, status) 
                VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
        $stmt = $this->db->prepare($sql);
        $stmt->execute([
            $data['notification_id'],
            $data['channel'],
            $data['type'],
            $data['title'],
            $data['content'],
            $data['receiver'],
            $data['data'],
            $data['status']
        ]);
        return $this->db->lastInsertId();
    }
    /**
     * 分发到具体渠道
     */
    private function dispatch($notification) {
        $channelClass = $this->channels[$notification['channel']];
        if (!class_exists($channelClass)) {
            throw new Exception("渠道类不存在: {$channelClass}");
        }
        $channel = new $channelClass();
        // 构建渠道数据
        $channelData = [
            'notification_id' => $notification['notification_id'],
            'title' => $notification['title'],
            'content' => $notification['content'],
            'receiver' => json_decode($notification['receiver'], true),
            'data' => json_decode($notification['data'], true)
        ];
        return $channel->send($channelData);
    }
    /**
     * 更新通知状态
     */
    private function updateNotificationStatus($id, $result) {
        $status = $result['status'] === 'success' ? 1 : 2;
        $sql = "UPDATE notifications SET status = ?, send_result = ?, sent_at = NOW() WHERE id = ?";
        $stmt = $this->db->prepare($sql);
        $stmt->execute([
            $status,
            json_encode($result),
            $id
        ]);
    }
    /**
     * 查询通知状态
     */
    public function query($notificationId) {
        $sql = "SELECT * FROM notifications WHERE notification_id = ?";
        $stmt = $this->db->prepare($sql);
        $stmt->execute([$notificationId]);
        $data = $stmt->fetch(PDO::FETCH_ASSOC);
        if (!$data) {
            return [
                'code' => 404,
                'message' => '通知不存在',
                'data' => null
            ];
        }
        $data['receiver'] = json_decode($data['receiver'], true);
        $data['data'] = json_decode($data['data'], true);
        $data['send_result'] = json_decode($data['send_result'], true);
        return [
            'code' => 200,
            'message' => '查询成功',
            'data' => $data
        ];
    }
}

渠道实现类

<?php
/**
 * 短信渠道
 */
class SmsChannel {
    public function send($data) {
        // 实现短信发送逻辑
        // 例如使用阿里云短信服务
        try {
            // 模拟发送
            $result = [
                'status' => 'success',
                'message' => '短信发送成功',
                'message_id' => 'MSG' . time(),
                'channel' => 'sms'
            ];
            // 实际调用短信SDK
            // $smsService = new AliyunSms();
            // $result = $smsService->send($data);
            return $result;
        } catch (Exception $e) {
            return [
                'status' => 'failed',
                'message' => $e->getMessage(),
                'channel' => 'sms'
            ];
        }
    }
}
/**
 * 邮件渠道
 */
class EmailChannel {
    public function send($data) {
        // 实现邮件发送逻辑
        try {
            // 模拟发送
            $result = [
                'status' => 'success',
                'message' => '邮件发送成功',
                'message_id' => 'EMAIL' . time(),
                'channel' => 'email'
            ];
            // 实际发送邮件代码
            // $mailer = new Mailer();
            // $result = $mailer->send($data);
            return $result;
        } catch (Exception $e) {
            return [
                'status' => 'failed',
                'message' => $e->getMessage(),
                'channel' => 'email'
            ];
        }
    }
}
/**
 * 推送渠道
 */
class PushChannel {
    public function send($data) {
        // 实现推送逻辑
        try {
            $result = [
                'status' => 'success',
                'message' => '推送成功',
                'message_id' => 'PUSH' . time(),
                'channel' => 'push'
            ];
            // 实际推送代码
            // $pushService = new PushService();
            // $result = $pushService->send($data);
            return $result;
        } catch (Exception $e) {
            return [
                'status' => 'failed',
                'message' => $e->getMessage(),
                'channel' => 'push'
            ];
        }
    }
}

HTTP接口调用示例

<?php
/**
 * 统一通知接口入口文件
 * api/notify.php
 */
// 设置响应头
header('Content-Type: application/json; charset=utf-8');
// 接收请求
$method = $_SERVER['REQUEST_METHOD'];
$uri = $_SERVER['REQUEST_URI'];
// 解析路由
$path = parse_url($uri, PHP_URL_PATH);
$action = basename($path);
require_once 'UnifiedNotification.php';
require_once 'SmsChannel.php';
require_once 'EmailChannel.php';
require_once 'PushChannel.php';
$db = getDatabaseConnection();
$notificationService = new UnifiedNotification($db);
switch ($method) {
    case 'POST':
        // 发送通知
        $params = json_decode(file_get_contents('php://input'), true);
        if ($action === 'batch') {
            $result = $notificationService->sendBatch($params);
        } else {
            $result = $notificationService->send($params);
        }
        break;
    case 'GET':
        // 查询通知
        $notificationId = $_GET['id'] ?? '';
        $result = $notificationService->query($notificationId);
        break;
    default:
        $result = [
            'code' => 405,
            'message' => '不支持的请求方法',
            'data' => null
        ];
}
echo json_encode($result, JSON_UNESCAPED_UNICODE);

调用示例

// 发送短信通知
$params = [
    'channel' => 'sms',
    'type' => 'verify_code', => '验证码',
    'content' => '您的验证码是:123456,5分钟内有效。',
    'receiver' => [
        'mobile' => '13800138000'
    ],
    'data' => [
        'template_id' => 'SMS_001',
        'code' => '123456'
    ]
];
// 发送邮件通知
$emailParams = [
    'channel' => 'email',
    'type' => 'order_confirmation', => '订单确认',
    'content' => '您的订单已确认,订单号:12345',
    'receiver' => [
        'email' => 'user@example.com'
    ],
    'data' => [
        'order_id' => '12345'
    ]
];

配置文件

<?php
// config/notification.php
return [
    // 渠道配置
    'channels' => [
        'sms' => [
            'driver' => 'aliyun',
            'access_key' => 'your_access_key',
            'secret_key' => 'your_secret_key',
            'sign_name' => '你的签名',
            'endpoint' => 'https://dysmsapi.aliyuncs.com'
        ],
        'email' => [
            'host' => 'smtp.example.com',
            'port' => 465,
            'username' => 'user@example.com',
            'password' => 'your_password'
        ],
        'push' => [
            'app_key' => 'your_app_key',
            'master_secret' => 'your_master_secret'
        ]
    ],
    // 重试配置
    'retry' => [
        'max_attempts' => 3,
        'delay_seconds' => 60
    ],
    // 日志配置
    'logging' => [
        'enabled' => true,
        'path' => '/path/to/notification.log'
    ]
];

这个统一通知接口设计具有以下特点:

  1. 统一入口:所有通知都通过同一个接口发送
  2. 多渠道支持:支持短信、邮件、推送等多种渠道
  3. 异步处理:可以扩展为队列异步处理
  4. 状态追踪:记录每条通知的发送状态
  5. 可扩展性:方便添加新的渠道
  6. 错误处理:完善的异常处理机制

您可以根据实际需求调整渠道实现和配置。

抱歉,评论功能暂时关闭!