5.0 KiB
架构与开发模式
技术栈
| 层 | 技术 | 说明 |
|---|---|---|
| 框架 | Laravel 12.65 | PHP ^8.2,declare(strict_types=1) 全量启用 |
| 后台 | Filament 5.7 | admin panel,zh_CN,资源/页面/组件 |
| 前台交互 | Livewire 4 | Filament 依赖 |
| 数据库 | MySQL 8(生产)/ SQLite(测试 :memory:) | |
| 缓存/队列 | database / redis | 队列默认 database,可切 redis |
| Markdown | league/commonmark(GFM)+ html-to-markdown | 内容双格式 |
| 附件 | S3 兼容(R2/COS/OSS)+ spatie/laravel-medialibrary | 零落盘 |
| 异步 | Workerman 5 常驻(队列消费者 + WebSocket) | 复用 Laravel Queue Worker |
| 支付 | yansongda/pay(支付宝/微信) | 沙箱模式内置 |
| 权限 | spatie/laravel-permission | admin/editor/member |
目录分层
app/
Blog/ # 前台域模块(与 Laravel 默认 app/ 分离)
Controllers/ # 前台控制器(theme_view() 渲染)
Jobs/ # AI 异步任务(AiJob 接口)
Services/ # 领域服务:渲染、支付、导入、S3 同步、LLM 客户端
Support/ # 基础设施:ThemeManager、PluginManager、SlugGenerator、MediaDisk、WorkermanBroadcaster
Providers/ # ThemeServiceProvider、PluginManagerServiceProvider
View/Composers/ # 侧边栏数据共享
Filament/ # 后台(Resources/Pages/Widgets)
Console/Commands/ # sablog:import / attachments:sync-s3 / workerman:serve / content:convert / theme:publish
Models/ # Post/Category/Comment/Link/Setting/User...
themes/ # 皮肤(theme.json + views + assets)
plugins/ # 插件(plugin.json + ServiceProvider + 迁移/路由/视图)
核心设计决策
-
内容双格式:
posts.content_format(markdown/html)。新文章默认 Markdown;老数据导入标记 html 原样保留,content:convert可批量转 Markdown。渲染管线PostContentRenderer::render()统一输出 HTML,再经post.rendered过滤器(付费内容等)。 -
附件短代码:HTML 内容
[attach=1]/[img=1];Markdown 内容用{{attach:1}}/{{img:1}}令牌([]是 Markdown 保留字符)。渲染时按全局 legacy_attachmentid 解析,找不到媒体自动清理残留。 -
主题系统:激活主题的 views 目录前置到全局视图路径(View Finder),主题覆盖同名视图、缺失回退默认视图。header 打开的容器由页面视图自闭合(避免 footer 错位)。资产开发期流式返回、生产
theme:publish。 -
插件系统:目录即插件(
plugins/{vendor}.{name}/plugin.json),钩子(action/filter)解耦。后台页面/资源通过 manifest 的filament_pages/filament_resources由PluginPages汇总注册。插件迁移自动加载。 -
S3 附件:上传磁盘 = s3(R2/COS/OSS endpoint),新上传零落盘;未配置 S3 时回退本地 public(开发友好)。
attachments:sync-s3幂等同步(含大文件 Multipart),损坏文件降级 pending 不中断。 -
异步 LLM:任务实现
AiJob接口,Workerman 常驻进程复用 LaravelQueue\Worker消费(database/redis 统一),sleep=0+ 1s Timer 不阻塞 event loop;失败重试failed_jobs表。 -
URL 兼容:canonical 前台 URL 统一
.shtml后缀(/posts/{slug}.shtml);无后缀版本 301;sablog 老 URL(伪静态/查询串/PHP 入口)全部 301;trackback 类垃圾功能直接 410 废弃。 -
迁移保 ID:
sablog:import用DB::table()->updateOrInsert保留老主键(Eloquent insertGetId 会忽略显式自增 id),老 MD5 密码登录时自动升级 bcrypt。
开发模式
- 本地:Herd 托管
laralog.test(PHP 8.2 + MySQL 8);无 S3 时附件落本地 public - 测试:PHPUnit,SQLite
:memory:(phpunit.xml),RefreshDatabase+seed();MySQL 专属 SQL(syncCounters)在 sqlite 兼容 - 常用命令:
php artisan sablog:import --fresh --convert-markdown(老库迁移)php artisan workerman:serve start|stopphp artisan testphp artisan theme:publish/content:convert --all/attachments:sync-s3
配置速查
| 配置 | 说明 |
|---|---|
config/blog.php |
站点/每页数/附件磁盘 |
config/themes.php |
主题目录/默认主题 |
config/plugins.php |
插件目录/内置启用列表 |
config/workerman.php |
消费者数/队列连接/队列名/重试 |
config/media.php |
S3 配置(R2/COS/OSS)与 Multipart 阈值 |
config/market.php |
插件/主题市场远程源 |
已知边界
- AI 审核/润色需要真实 LLM Key(OpenAI 兼容);支付需真实网关密钥(沙箱已验证)
- 插件/主题市场客户端已就绪,市场服务端需另行部署(接口约定见
App\Blog\Services\MarketplaceClient) - 自动配图(封面生成)为后续迭代项:封面媒体集合与主题展示已就位,生成器走队列/脚本