six-shop / news
资讯,文章,新闻,公告发布
Installs: 25
Dependents: 0
Suggesters: 0
Security: 0
Type:sixshop-extension
pkg:composer/six-shop/news
Requires
- php: >=8.3
 - six-shop/core: >=0.5.8 <1.0
 
README
模块功能
本模块为 SixShop 系统提供资讯管理功能。其核心业务逻辑(数据库 CRUD)完全由 Go 语言实现,并通过 PHP FFI 进行调用。这种方式可以有效保护核心业务逻辑代码,同时利用 Go 的高性能特性。
主要特性
- 后台管理:
- 资讯分类管理 (增删改查)
 - 资讯文章管理 (增删改查)
 
 - API 接口:
- 获取资讯分类列表
 - 获取指定分类下的文章列表(支持分页)
 - 获取文章详情
 
 - Go FFI 实现:
- 所有数据库操作均在编译好的 Go 共享库 (
.so) 中执行。 - PHP 服务层仅作为调用 FFI 接口的桥梁。
 
 - 所有数据库操作均在编译好的 Go 共享库 (
 
目录结构
backend/extension/news/
├── config/
│   ├── install.sql       # 数据库表结构
│   └── uninstall.sql     # 卸载表结构
├── ffi/
│   ├── main.go           # Go FFI 业务逻辑和导出函数
│   ├── go.mod            # Go 依赖管理
│   ├── Makefile          # 一键构建 Go 共享库的脚本
│   ├── model/
│   │   ├── category.go   # 资讯分类 GORM 模型
│   │   └── news.go       # 资讯文章 GORM 模型
│   ├── lib_news.so       # [构建产物] Go 编译的共享库
│   └── lib_news.h        # [构建产物] Go 编译的头文件
├── route/
│   ├── admin.php         # 后台路由
│   └── api.php           # 前端API路由
├── src/
│   ├── Controller/
│   ├── Model/            # ThinkPHP 模型 (仅用于框架集成, 不含业务逻辑)
│   ├── Service/
│   │   ├── NewsCategoryService.php # 分类服务的 FFI 调用封装
│   │   ├── NewsService.php         # 资讯服务的 FFI 调用封装
│   │   └── NewsFfiService.php      # [核心] FFI 单例服务, 负责加载和调用 .so 文件
│   └── Hook/
├── news.info.yml         # 模块信息
└── README.md             # 模块说明文档
数据库安装
- 在插件安装时,需执行 
config/install.sql文件,以创建cy_news_category和cy_news两张表。 
核心依赖
- Go 1.20+
 - Docker (用于执行 
Makefile中的构建命令) - PHP 7.4+ 并已启用 FFI 扩展
 
宝塔面板环境启用 PHP FFI 教程
以下步骤以宝塔面板安装的 PHP 8.3 为例,其他版本仅需替换路径中的版本号。
1. 进入 FFI 源码目录
cd /www/server/php/83/src/ext/ffi
若提示目录不存在,请先在宝塔面板的 PHP 设置中执行一次“重新安装源码”。
2. 生成编译配置
phpize
执行成功后会生成 configure 等构建文件。
3. 配置并编译扩展
./configure --with-php-config=/www/server/php/83/bin/php-config
make && make install
完成后系统会在 /www/server/php/83/lib/php/extensions/ 下生成 ffi.so。
4. 配置 php.ini
在宝塔面板中打开 PHP 8.3 的 php.ini,或直接修改 /www/server/php/83/etc/php.ini,追加:
extension=ffi
ffi.enable=true
如果使用 PHP-FPM,请同步在 php.d 或额外的配置文件中开启上述参数,确保 CLI 与 FPM 环境都能加载 FFI。
5. 重启 PHP 服务
在宝塔面板中重启对应 PHP 版本的服务,或执行:
bt restart php 83
6. 验证扩展是否生效
/www/server/php/83/bin/php -m | grep FFI
若输出包含 FFI,说明扩展已启用。也可使用 php -i | grep -i ffi 查看详细配置。
完成以上步骤后,即可在 news 插件中通过 PHP FFI 加载 Go 动态库。
构建 Go 共享库
所有 Go 源代码的编译都通过 Makefile 完成。
# 进入 ffi 目录
cd backend/extension/news/ffi
# 执行构建
make build
该命令会使用 Docker 容器来编译 Go 代码,确保构建环境的一致性。成功后,会在当前目录下生成 lib_news.so 和 lib_news.h 两个文件。
PHP FFI 调用流程
NewsFfiService通过单例模式加载lib_news.so文件,并根据lib_news.h的内容定义 C 函数签名。NewsService和NewsCategoryService在实例化时会获取NewsFfiService的单例。- 当控制器调用 
NewsService的方法时(如getList),NewsService会将请求参数(如查询条件、分页信息)打包成 JSON 字符串。 NewsService调用NewsFfiService的相应方法,将 JSON 字符串作为参数传递给 Go 函数。- Go 函数接收参数,执行数据库操作,并将结果打包成 JSON 字符串返回。
 NewsFfiService接收返回的 JSON 字符串,并将其解码为 PHP 数组,最终返回给控制器。
FFI 接口清单 (Go -> PHP)
所有业务逻辑都已封装在以下 Go 函数中,并通过 FFI 导出:
GetCategoryList(char* whereJson)GetCategoryByID(int id)CreateCategory(char* dataJson)UpdateCategory(int id, char* dataJson)DeleteCategory(int id)GetNewsList(char* paramsJson)GetNewsByID(int id)CreateNews(char* dataJson)UpdateNews(int id, char* dataJson)DeleteNews(int id)
注意事项
- 路径依赖: 
NewsFfiService.php中硬编码了lib_news.so的相对路径。如果移动文件,需要同步更新。 - 重新编译: 任何对 
ffi/目录下.go文件的修改,都必须重新执行make build才能生效。 - 错误处理: Go FFI 函数中的错误会以包含 
error键的 JSON 字符串形式返回,PHP 服务层应进行相应的检查和处理。 
服务层依赖注入分析
在 news 模块的控制器中,存在两种不同的服务层依赖注入(或实例化)方式。这两种方式在设计上存在差异,体现了不同的架构思路。
方式一:通过适配器实例化 (Admin 控制器)
此方式应用于 src/Controller/Admin/ 目录下的所有控制器。
实现: 控制器在其构造函数中,通过
new关键字直接实例化一个适配器 (NewsServiceAdapter或NewsCategoryServiceAdapter)。// 文件: backend/extension/news/src/Controller/Admin/NewsController.php use SixShop\News\Service\NewsServiceAdapter; class NewsController { protected $service; public function __construct() { // 直接实例化适配器 $this->service = new NewsServiceAdapter(); } // ... }- 优点:
- 松耦合: 控制器本身不关心底层的具体实现。所有的业务逻辑切换(例如,在开发模式下使用纯 PHP 服务,在生产模式下使用 FFI 服务)都封装在适配器内部。
 - 符合依赖倒置原则: 控制器依赖于一个稳定的"适配器"抽象,而不是一个多变的具体服务。
 - 易于维护和扩展: 如果未来需要增加新的服务实现,只需要修改适配器,控制器代码无需改动。
 
 - 结论: 这是项目推荐的、更健壮、更灵活的设计模式。
 
方式二:通过构造函数依赖注入 (Api 控制器)
此方式应用于 src/Controller/Api/ 目录下的控制器。
实现: 控制器在其构造函数的参数中,声明需要注入的具体服务 (
NewsService),由框架的依赖注入容器自动实例化并传入。// 文件: backend/extension/news/src/Controller/Api/NewsController.php use SixShop\News\Service\NewsService; class NewsController { private $service; public function __construct(NewsService $service) { // 由框架注入具体的 NewsService 实例 $this->service = $service; } // ... }- 缺点:
- 紧耦合: 控制器与具体的 
NewsService类紧密绑定。 - 缺乏灵活性: 它无法利用适配器模式带来的好处。如果想为 API 控制器也实现开发/生产模式的切换,就必须重构其构造函数和依赖关系。
 - 设计不一致: 与 Admin 控制器的实现方式不统一,增加了项目的维护成本和认知负担。
 
 - 紧耦合: 控制器与具体的 
 - 改进建议: 为了保持整个模块架构的一致性,建议未来将 Api 控制器的实现方式重构为方式一(使用适配器)。
 
API 接口说明
本插件提供两组符合 RESTful 规范的资源路由,分别用于后台管理和前端调用。
后台管理 API
路由前缀: /admin/extension/news
所有后台接口均会通过 Auth 中间件进行权限验证。
1. 资讯分类管理 (/category)
- 获取分类列表: 
GET /category- 说明: 获取所有资讯分类,支持 
name字段模糊查询。 - 示例: 
GET /admin/extension/news/category?name=技术 
 - 说明: 获取所有资讯分类,支持 
 - 获取单个分类: 
GET /category/{id}- 说明: 获取指定 ID 的分类详情。
 
 - 新增分类: 
POST /category- 说明: 创建一个新的资讯分类。
 - 请求体 (JSON): 
{ "name": "新分类", "sort": 100, "status": 1 } 
 - 更新分类: 
PUT /category/{id}- 说明: 更新指定 ID 的分类信息。
 - 请求体 (JSON): 
{ "name": "更新后的分类", "sort": 99 } 
 - 删除分类: 
DELETE /category/{id}- 说明: 删除指定 ID 的分类。
 
 
2. 资讯文章管理 (/news)
- 获取文章列表: 
GET /news- 说明: 获取所有资讯文章,支持分页,支持按 
title和category_id查询。 - 示例: 
GET /admin/extension/news/news?title=六店&category_id=1&page=1&limit=10 
 - 说明: 获取所有资讯文章,支持分页,支持按 
 - 获取单篇文章: 
GET /news/{id}- 说明: 获取指定 ID 的文章详情。
 
 - 新增文章: 
POST /news- 说明: 创建一篇新的资讯文章。
 - 请求体 (JSON): 
{ "category_id": 1, "title": "文章标题", "content": "文章内容...", "status": 1 } 
 - 更新文章: 
PUT /news/{id}- 说明: 更新指定 ID 的文章信息。
 - 请求体 (JSON): 
{ "title": "更新后的标题" } 
 - 删除文章: 
DELETE /news/{id}- 说明: 删除指定 ID 的文章。
 
 
移动端 API
路由前缀: /api/extension/news
1. 资讯分类接口 (/category)
- 获取分类列表: 
GET /category- 说明: 获取所有已启用的资讯分类列表。
 
 
2. 资讯文章接口 (/news)
- 获取文章列表: 
GET /news- 说明: 获取所有已发布的资讯文章,支持按 
category_id筛选和分页。 - 示例: 
GET /api/extension/news/news?category_id=1&page=1&limit=10 
 - 说明: 获取所有已发布的资讯文章,支持按 
 - 获取文章详情: 
GET /news/{id}- 说明: 获取一篇已发布的文章详情。
 
 
数据库安装与卸载
- 安装表结构:
- 执行 
config/install.sql,自动创建资讯分类表(cy_news_category)和资讯文章表(cy_news)。 
 - 执行 
 - 卸载表结构:
- 执行 
config/uninstall.sql,自动删除本模块相关表结构。 
 - 执行 
 
推荐在模块安装、升级、卸载时自动调用对应 SQL,便于独立管理和维护。
FFI 动态库能力说明
本模块内置 Go FFI 动态库(ffi/ 目录),用于高性能、可闭源的资讯业务处理,PHP 可通过 FFI 调用。
依赖安装
- 需 Go 1.20+
 - 依赖 GORM、yaml.v2
 - 安装依赖:
 
cd ffi
go mod tidy
数据库配置
- 配置文件:
config/db.yaml - 支持 MySQL,参数与 PHP 项目一致
 
构建动态库
- 推荐用 Makefile 一键构建:
 
cd ffi
make build
# 生成 lib_news.so 和 lib_news.h
- 也可用 Dockerfile 构建
 
主要接口
GetList()获取资讯列表(JSON)GetById(id)获取单条资讯详情(JSON)Create(json)新增资讯,参数为 JSONUpdate(id, json)编辑资讯Delete(id)删除资讯GenerateSummary(content)生成摘要CheckContent(content)内容审核ExtractKeywords(content)关键词提取
PHP FFI 调用示例
$ffi = FFI::cdef(file_get_contents('lib_news.h'), 'lib_news.so');
$list = json_decode(FFI::string($ffi->GetList()), true);
$info = json_decode(FFI::string($ffi->GetById(1)), true);
$id = $ffi->Create(json_encode($data));
$ok = $ffi->Update($id, json_encode($data));
$ok = $ffi->Delete($id);
$summary = FFI::string($ffi->GenerateSummary($content));
$isIllegal = $ffi->CheckContent($content);
$keywords = explode(',', FFI::string($ffi->ExtractKeywords($content)));
注意事项
- 动态库需与 PHP FFI 路径一致
 - 数据库表结构需提前安装(见 config/install.sql)
 - 推荐配合 PHP Service 层切换调用
 
插件编译与分发
一键编译与分发
- 推荐使用 shell 脚本(需 bash 环境):
cd backend/extension/news ./build.sh - 或使用 PHP 脚本(适合 PHP-only 环境):
cd backend/extension/news php build.php 
编译/分发脚本高级特性
- 增量编译:自动检测 ffi/ 下所有 Go 源码变更,无变更则跳过 make build,极大提升效率。
 - 编译日志:所有编译和打包输出写入 
build/build.log,便于排查问题。 - 自动打包:编译完成后自动将 
build/目录内容打包为build/package.zip,方便分发和备份。 - 产物一致:无论用 shell 还是 PHP 脚本,体验和产物完全一致。
 
编译产物
build/lib_news.so、build/lib_news.h:Go FFI 动态库及头文件build/NewsServiceFFI.php:PHP FFI 适配层,控制器/接口直接调用build/package.zip:自动打包的分发包build/build.log:编译和打包日志
开发与分发模式
- 开发模式:保留全部源码,便于调试和测试
 - 分发模式:只保留 build 目录和必要接口,核心业务完全闭源
 
控制器调用 FFI 适配层示例
require_once __DIR__ . '/../build/NewsServiceFFI.php';
$service = new NewsService();
$list = $service->getList();
服务适配层(ServiceAdapter)设计说明
为实现开发模式(PHP Service)与分发模式(FFI 适配层)的无缝切换,所有控制器均依赖适配层(如 NewsServiceAdapter、NewsCategoryServiceAdapter),而不直接依赖具体 Service 实现。
- 开发模式:适配层自动加载并调用 PHP Service,便于本地开发和调试。
 - 分发模式:适配层自动加载并调用 FFI 适配层(build/NewsServiceFFI.php),核心逻辑闭源,安全分发。
 - 控制器层代码无需变动,适配层自动切换底层实现。
 
控制器用法示例
$service = new NewsServiceAdapter();
$list = $service->getList();
适配层代码位于 src/Service/NewsServiceAdapter.php、src/Service/NewsCategoryServiceAdapter.php,可根据实际业务扩展更多方法。