six-shop/news

资讯,文章,新闻,公告发布

Maintainers

Details

gitee.com/sixdec-1/news.git

Installs: 5

Dependents: 0

Suggesters: 0

Security: 0

Type:sixshop-extension

v0.1.2 2025-08-29 16:21 UTC

This package is auto-updated.

Last update: 2025-08-29 16:22:23 UTC


README

模块功能

本模块为 SixShop 系统提供资讯管理功能。其核心业务逻辑(数据库 CRUD)完全由 Go 语言实现,并通过 PHP FFI 进行调用。这种方式可以有效保护核心业务逻辑代码,同时利用 Go 的高性能特性。

主要特性

  • 后台管理:
    • 资讯分类管理 (增删改查)
    • 资讯文章管理 (增删改查)
  • API 接口:
    • 获取资讯分类列表
    • 获取指定分类下的文章列表(支持分页)
    • 获取文章详情
  • Go FFI 实现:
    • 所有数据库操作均在编译好的 Go 共享库 (.so) 中执行。
    • PHP 服务层仅作为调用 FFI 接口的桥梁。

目录结构

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_categorycy_news 两张表。

核心依赖

  • Go 1.20+
  • Docker (用于执行 Makefile 中的构建命令)
  • PHP 7.4+ 并已启用 FFI 扩展

构建 Go 共享库

所有 Go 源代码的编译都通过 Makefile 完成。

# 进入 ffi 目录
cd backend/extension/news/ffi

# 执行构建
make build

该命令会使用 Docker 容器来编译 Go 代码,确保构建环境的一致性。成功后,会在当前目录下生成 lib_news.solib_news.h 两个文件。

PHP FFI 调用流程

  1. NewsFfiService 通过单例模式加载 lib_news.so 文件,并根据 lib_news.h 的内容定义 C 函数签名。
  2. NewsServiceNewsCategoryService 在实例化时会获取 NewsFfiService 的单例。
  3. 当控制器调用 NewsService 的方法时(如 getList),NewsService 会将请求参数(如查询条件、分页信息)打包成 JSON 字符串。
  4. NewsService 调用 NewsFfiService 的相应方法,将 JSON 字符串作为参数传递给 Go 函数。
  5. Go 函数接收参数,执行数据库操作,并将结果打包成 JSON 字符串返回。
  6. 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 关键字直接实例化一个适配器 (NewsServiceAdapterNewsCategoryServiceAdapter)。

    // 文件: 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
    • 说明: 获取所有资讯文章,支持分页,支持按 titlecategory_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) 新增资讯,参数为 JSON
  • Update(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.sobuild/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.phpsrc/Service/NewsCategoryServiceAdapter.php,可根据实际业务扩展更多方法。