[开发]SoSite 1.0 — 插件迁移计划(数据库独立目录方案)

👑Lv.11 元老 🌞 骨干会员
2026-10-25 00:57:24

本文由 FlintHub 开发文档归档发布。原始文档日期见标题前缀,来源:暂存20260913/docs/插件迁移计划 (2).md。

SoSite 1.0 — 插件迁移计划(数据库独立目录方案)

文档状态:待确认(2026-08-13)

目标:恢复插件系统(P0~P6 已暂停迁移),并将每个插件的数据库独立存放于插件自身目录

原则:插件数据不再写入全局 business.sqlite;每个插件一个独立 SQLite 文件;核心库只读访问保留


一、现状勘察(已读代码确认)

1.1 插件清单(16 个)与数据表映射

插件中文名自有数据表依赖核心库备注
announcements公告announcementssettingsactivate/uninstall 建删表
content_review内容审核content_reviews、review_notificationsthreads/postshook 内也有建表
daily_checkin每日签到daily_checkinusers(积分)activate + init_after 双处建表
dice掷骰子无表无纯随机,无需数据库
edit_info编辑历史edit_history—post/thread_edit_after hook 建表
friend_links友情链接friend_links—Admin/Front 双控制器
icon_generator图标生成无表无前端工具
invite邀请注册invitesusersinit_after 建表
medal勋章系统medals、user_medals、user_medal_wearsusersactivate + init_after 双处建表
notifications通知系统notifications—多 hook 读写
post_favorite帖子收藏post_favoritesthreads—
quiz_duel答题对决quiz_duels 等—说明.md 列示
red_packet红包red_packets、red_packet_claimsusers(积分)双表 + 索引
seoSEO 优化无自有表threads/blogs/categories/settings(只读)仅读核心库,无建表
user_profile用户主页user_followsusers—

1.2 现状问题(已确认)

  1. 全部插件使用全局库:\app\Core\Database::getInstance() → business.sqlite,插件表与核心表混居一库
  2. 建表为 MySQL 语法:SHOW TABLES LIKE 'x'、INT AUTO_INCREMENT PRIMARY KEY、DATETIME、VARCHAR(n)、UNIQUE KEY、INDEX、NOW() 等——SQLite 下无法执行
  3. 插件系统当前"暂停":Plugin::init() 与全部 Plugin::hook() 调用已被 // [SplitDB] 临时注释: 注释(P0~P6 阶段),需恢复
  4. 旧数据未迁移:migrate.php B2 只迁了 17 张核心表,插件表(announcements/daily_checkin/edit_history 等)仍在旧 MySQL fastbb 库中,dry-run 时可见(announcements 3 行、daily_checkin 36 行、edit_history 57 行…)

二、目标架构

plugins/{插件名}/
  Plugin.php          ← activate/deactivate/uninstall(建表/删表)
  hook/*.php          ← 钩子逻辑(读写改走插件库)
  data/
    {插件名}.sqlite   ★ 本插件独立数据库(DBFactory 连接,统一 PRAGMA)
  plugin.json / views / assets

  • 数据流:插件自有表读写 → Plugin::db($name)(新增,经 DBFactory 连 plugins/{name}/data/{name}.sqlite)
  • 核心库只读(seo 读 threads/blogs/categories、通知读帖子标题等)→ 保留 Database::getInstance() 只读访问
  • 插件间不共享数据,互不依赖

三、改造执行计划表(待确认后串行,每步自测)

#任务交付物验证方式
P1核心支撑:Plugin.php 新增 db($name)(插件独立库连接,幂等建 data/ 目录 + DBFactory + 统一 PRAGMA);新增 Plugin::ensureSchema($name, $ddl) 助手(SQLite DDL 幂等建表)app/Helpers/Plugin.php临时脚本:对任意插件名建独立库、建表、读写往返
P2恢复插件系统骨架:恢复 app/init.php 的 Plugin::init();全站取消 Plugin::hook 的临时注释(Controllers/Views/index.php,恢复后插件钩子开始触发)app/init.php + 各处 hook 还原页面可渲染、无插件报错(先只开 activate 幂等)

| P3 | 逐插件改造(按依赖从简到繁):

  • 无表组:dice、icon_generator(仅改 getInstance 引用即可,无库)
  • 单表组:announcements、daily_checkin、edit_info、friend_links、invite、notifications、post_favorite、user_profile、quiz_duel
  • 多表组:content_review(2 表)、medal(3 表)、red_packet(2 表)
  • 只读组:seo(无建表,保留核心库只读) | 各插件 Plugin.php/hook/Controller | 每插件:activate 建表成功、页面功能走通、uninstall 删表 |

| P4 | 插件数据迁移脚本:cli/migrate_plugins.php——从旧 MySQL(fastbb)按插件表清单读取 → 写入各插件独立库(列白名单 + 显式 ID 保外键) | 新脚本 | --dry-run 行数预览 + 真实迁移 + 抽查行数一致 |

| P5 | 交付:update/ 同步 + CHANGELOG.md 追加 | 交付物 | 与根目录 diff 一致;php -l 全过 |


四、关键技术设计

4.1 插件独立库连接(P1 核心)

// app/Helpers/Plugin.php 新增
public static function db(string $name): \PDO
{
    $dir = self::$pluginDir . '/' . $name . '/data';
    if (!is_dir($dir)) @mkdir($dir, 0755, true);
    return \app\SplitDB\DBFactory::getConnection($dir . '/' . $name . '.sqlite');
}

  • 复用 DBFactory:统一 6 条 PRAGMA(WAL/busy_timeout 等)、LRU 池、路径归一化,零新增连接管理代码
  • 幂等:data/ 目录缺失自动创建

4.2 SQLite DDL 转换规则(P3 逐插件)

MySQL 写法SQLite 等价
id INT AUTO_INCREMENT PRIMARY KEYid INTEGER PRIMARY KEY
VARCHAR(n) / DATETIMETEXT
SHOW TABLES LIKE 'x' 探测直接 CREATE TABLE IF NOT EXISTS(幂等)或 PRAGMA table_info
UNIQUE KEY uk (a,b)UNIQUE(a,b)(表内)或独立 CREATE UNIQUE INDEX IF NOT EXISTS
INDEX idx (a)CREATE INDEX IF NOT EXISTS idx ON t (a)
NOW()PHP time() / date('Y-m-d H:i:s') 参数绑定

4.3 数据迁移(P4)

  • 数据源:旧 MySQL fastbb(复用 migrate.php 的连接参数机制 --host/--name/--user/--pass)
  • 表清单:P1 表中"自有数据表"列(约 18 张),按插件归属迁移到对应独立库
  • 规则:列白名单(仅迁目标表存在的列)、显式 ID、_runtime_* 类跳过、迁移后各插件库行数与旧库一致

4.4 恢复钩子的范围(P2)

  • app/init.php:Plugin::init() 恢复
  • Controllers / Views / index.php:约 25+ 处 // [SplitDB] 临时注释: 还原(按 CHANGELOG P5/P6 记录的位置逐一恢复)
  • 恢复顺序注意:先恢复 init() 与 activate() 链路(建表),再恢复业务钩子,避免钩子触发时表不存在

五、风险与红线

  1. 不删插件代码(沿用补充要求 #4):所有恢复均为"去掉注释前缀",原始代码保留
  2. 数据安全:插件表迁移失败 → 报错中止,不产生部分残留;迁移前 --dry-run 预览
  3. 兼容:插件同时兼容"已迁移独立库"与"全新安装"两种状态(activate 幂等建表)
  4. seo 等只读插件:不建独立库,保留核心库只读——避免重复数据
  5. 全部文件 UTF-8 no BOM + LF;php -l 校验;每插件改造后立即自测

六、验收流程(用户侧)

  1. 后台 → 插件管理 → 逐个激活插件(announcements → medal → red_packet…)
  2. 每插件功能走通:公告展示、每日签到、编辑历史、收藏、通知、勋章佩戴、红包发放、答题对决…
  3. 检查 plugins/{插件名}/data/{插件名}.sqlite 已生成且独立(不依赖 business.sqlite)
  4. 跑 cli/migrate_plugins.php --dry-run → 全量 → 抽查旧数据行数一致
  5. 卸载某插件 → 独立库删除、核心库无残留

七、待用户确认点

  1. 独立库路径:plugins/{插件名}/data/{插件名}.sqlite(推荐)还是 plugins/{插件名}/db.sqlite 或别的?
  2. 迁移范围:插件旧数据(fastbb 中约 18 张插件表)是否本次一并迁移?(推荐一并做,否则新装无历史数据)
  3. 插件激活范围:全部 16 个插件都恢复,还是先恢复核心几个(公告/签到/收藏/通知/勋章)验证后再全量?
轻量级、高性能、零 MySQL 依赖的PHP社区系统。
| 瀏覽 6 次 | 回覆 0 次

全部回覆 (0)

暫無回覆

請 登入