简介
本开发文档面向电商开发者,系统性梳理 DouPHP 商品管理系统的商品模型设计、属性管理、分类体系、库存控制、价格管理、CRUD 流程、批量操作、搜索过滤、状态管理等核心能力。文档同时给出代码级架构图与调用时序图,帮助快速定位实现位置并指导二次开发(如扩展属性、新增商品类型、自定义验证规则等)。
项目结构
商品管理采用“控制器-服务-模型”的分层组织方式,围绕 product、attribute、item 三个模块展开:
- 后台控制器负责路由与视图数据组装,校验由 FormRequest 完成,业务逻辑下沉至 Service。
- 模型封装数据表映射、关联关系、查询作用域与删除清理策略。
- 服务层协调附件、Markdown、定价、审计日志等横切能力。
graph TB
subgraph "后台"
PC["ProductController"]
PS["ProductService"]
PM["Product Model"]
PAC["ProductCategory Model"]
ASvc["AttributeService"]
AM["Attribute / AttributeValue Models"]
end
PC --> PS
PS --> PM
PS --> PAC
PC --> PAC
PC --> ASvc
ASvc --> AM
核心组件
- 商品模型(Product)
- 字段白名单包含标题、别名、价格、促销价、会员价、库存、内容、主图、积分、关键词、描述、排序、创建时间等。
- 提供关键字筛选、默认排序、仅上架筛选、工作台归属筛选等作用域。
- 维护型号串(model)的生成、唯一性、清空与同步;删除时清理图库与多语言记录。
- 商品服务(ProductService)
- 列表构建:分页、分类过滤、关键字过滤、格式化价格与会员价档位、图片 URL 预热。
- 新增/更新:处理主图上传、正文远程图片本地化、会员价序列化、审计日志。
- 缩略图批量重建:流式输出进度与结果。
- 型号关联:按 model 分组展示与解绑。
- 删除与批量操作:二次确认、批量改分类、批量删除。
- 商品分类(ProductCategory)
- 树形分类能力,支持扁平化输出供下拉选择。
- 属性体系(Attribute / AttributeValue)
- 属性按商品分类筛选(含子分类与全局属性),支持文本/图片等类型。
- 属性值支持价格变动、备注、图片,并提供 AJAX 增删改查。
- 内容项(Item)
- 通用内容模型,具备分类、图片、价格、原始价、文件大小等字段,便于复用。
架构总览
商品管理的请求链路遵循“控制器→服务→模型”的分层模式,关键路径如下:
- 列表:控制器接收参数 → 服务分页查询 → 模型作用域过滤 → 返回模板数据。
- 新增/编辑:控制器校验 → 服务处理附件与内容 → 写入数据库 → 写审计日志。
- 删除:控制器二次确认 → 服务执行删除 → 清理附件与多语言记录。
- 属性:控制器/前端通过 AJAX 调用属性服务,动态增删属性值并刷新 UI。
sequenceDiagram
participant U as "管理员"
participant C as "ProductController"
participant S as "ProductService"
participant M as "Product Model"
participant A as "Attachment/Markdown/Pricing"
U->>C : 访问商品列表/表单
C->>S : 构建列表/默认数据
S->>M : 查询(分类/关键字/排序)
M-->>S : 数据集
S-->>C : 视图数据
C-->>U : 渲染页面
U->>C : 提交新增/更新
C->>S : insert/update(data, adminId)
S->>A : 处理主图/正文/会员价
S->>M : create/fill+save
S-->>C : 成功/异常
C-->>U : 跳转/提示
详细组件分析
商品模型(Product)
- 数据表与字段
- 表名:product
- 可批量写入字段:operator_type/operator_id/category_id/brand_id/title/slug/price/promote_price/level_price/stock/defined/content/image/point/keywords/description/sort/created_at
- 关联关系
- 分类:belongsTo ProductCategory
- 查询作用域
- filterByKeyword:按标题模糊匹配
- applyDefaultOrder:根据配置决定 sort/id 排序
- published:仅上架
- ownedByWork:工作台权限边界
- 生命周期与清理
- 删除前:清理图库附件与多语言记录
- 型号串(model)
- ensureOrCreateModelNumber:缺失则生成唯一号并回写
- setModelById/clearModelById/clearModelByModelString:用于型号组管理
- getGalleryFileNumberRows:删除前收集附件编号
classDiagram
class Product {
+string table
+array fillable
+category()
+scopeFilterByKeyword(query, keyword)
+scopeApplyDefaultOrder(query)
+scopePublished(query)
+scopeOwnedByWork(query, workId)
+ensureOrCreateModelNumber(id) string
+setModelById(productId, model) void
+clearModelById(productId) void
+clearModelByModelString(model) void
+getGalleryFileNumberRows(productId) array
}
class ProductCategory {
+string table
+array fillable
}
Product --> ProductCategory : "belongs to"
商品服务(ProductService)
- 列表构建
- 分页、分类过滤、关键字过滤、格式化价格与会员价档位、图片 URL 预热
- 新增
- 校验草稿令牌与管理员ID
- 会员价序列化、正文 XSS 过滤与远程图片本地化
- 主图上传并生成缩略图
- 写入审计日志
- 编辑
- 读取记录并转换为模板格式(图片URL、型号列表、Markdown 预览、自定义字段)
- 更新
- 校验存在性、处理主图/正文、写入并记录日志
- 缩略图批量重建
- 计算待处理数量、逐条生成缩略图并通过 JS 更新进度遮罩
- 型号关联
- add:为当前商品生成/使用统一 model 并绑定到目标商品
- del:解除绑定或清空整组
- 删除与批量操作
- 单删:二次确认、审计日志、清理资源
- 批量:del_all、category_move
flowchart TD
Start(["开始"]) --> Check["校验参数<br/>草稿令牌/管理员ID"]
Check --> |合法| Process["处理主图/正文/会员价"]
Check --> |非法| Err["抛出异常/返回错误"]
Process --> Save["持久化到数据库"]
Save --> Log["记录审计日志"]
Log --> End(["结束"])
商品控制器(ProductController)
- 列表页:接收 category_id/keyword/page,调用服务构建数据并渲染
- 新增/编辑:准备默认数据、加载分类/品牌/用户等级选项、多语言按钮
- 提交:委托服务处理,成功后重定向并提示
- 缩略图批量:确认后进行流式重建
- 型号关联:Ajax 接口,参数校验后调用服务
- 删除:二次确认后执行删除
- 批量操作:批量删除/批量改分类
商品分类(ProductCategory)
- 树形分类能力,支持 flat() 扁平化输出
- 与商品通过 category_id 关联
属性体系(Attribute / AttributeValue)
- 属性
- 按商品分类筛选(含子分类与全局属性)
- 默认排序:sort ASC, id ASC
- 删除保护:若存在属性值则阻止删除
- 属性值
- 支持 module/item_id/att_id/value/type/image/remark/price_change
- AJAX 增删改:add/del/image,统一 ApiResponse 五段包络
- 价格联动
- 首次添加属性值且 price_change > 0 时提示约束
- 前端根据选中属性值累加价格(主题脚本中体现)
sequenceDiagram
participant FE as "前端"
participant AS as "AttributeService"
participant AV as "AttributeValue Model"
participant ATT as "Attachment"
FE->>AS : processValueAjax('add', {module,item_id,att_id,value,...})
AS->>AV : 查重/校验
alt 重复或为空
AS-->>FE : 422 错误 + HTML片段
else 新增成功
AS->>ATT : 可选图片上传
AS-->>FE : 200 + HTML片段
end
内容项(Item)
- 通用内容模型,具备分类、图片、价格、原始价、文件大小等字段
- 提供关键字筛选与默认排序作用域
- 可作为商品之外的另一种内容载体
依赖关系分析
- 控制器依赖服务与模型
- 服务依赖模型、附件系统、Markdown 渲染、定价服务、审计日志
- 模型依赖 ORM、配置、工具类、附件清理策略
graph LR
PC["ProductController"] --> PS["ProductService"]
PS --> PM["Product Model"]
PS --> PAC["ProductCategory Model"]
PS --> ATT["Attachment/Storage"]
PS --> MD["MarkdownRenderer"]
PS --> PR["PricingService"]
PS --> AUD["AdminLog"]
PC --> PAC
性能与缓存
- 列表优化
- 使用 with('category') 预加载分类,减少 N+1 查询
- 使用 casts 中的 attachment 预取器批量预热图片 URL
- 分页限制每页 30 条,避免大结果集
- 缩略图批量重建
- 流式输出进度,降低内存占用,提升用户体验
- 内容渲染
- Markdown 渲染在编辑页按需进行,避免频繁转换
- 建议
- 对高频读场景可引入缓存(如分类树、品牌列表)
- 对商品详情页可结合 CDN 缓存静态资源
- 对大数据量导入导出建议使用队列与分批处理
故障排查指南
- 新增/更新失败
- 检查表单校验(FormRequest)是否通过
- 检查草稿令牌与管理员 ID 是否有效
- 查看附件上传路径与权限
- 删除报错
- 确认是否存在属性值(属性删除保护)
- 确认商品是否存在
- 列表无数据
- 检查分类过滤与关键字条件
- 检查排序配置与状态筛选
- 缩略图未生成
- 检查磁盘配置与图片质量参数
- 确认源图绝对路径与缩略图命名规则
结论
DouPHP 商品管理系统以清晰的分层架构实现了商品全生命周期管理,涵盖分类、属性、价格、库存、状态、批量操作与附件处理等核心能力。通过模型作用域与服务编排,既保证了可扩展性,也兼顾了性能与可维护性。开发者可基于现有能力快速扩展新属性、新商品类型与自定义验证规则。
附录:扩展与最佳实践
扩展商品属性
- 新增属性定义
- 在属性管理中新增属性,设置分类与作用域
- 绑定到商品
- 在商品编辑页通过属性面板添加属性值,支持价格变动与图片
- 参考实现
- 属性列表与 CRUD:AttributeService.php:53-163
- 属性值 AJAX 操作:AttributeService.php:210-343
- 属性模型筛选:Attribute.php:45-76
新增商品类型
- 方案一:复用 Item 作为内容型商品
- 使用 Item 模型的分类、图片、价格、原始价、文件大小等字段
- 参考:Item.php:31-127
- 方案二:扩展 Product 模型
- 在 Product 中增加 type 字段与作用域筛选
- 在服务层按 type 分支处理差异化逻辑(如价格、库存、附件)
自定义商品验证规则
- 在 FormRequest 中追加 rules(例如:价格区间、库存非负、必填字段)
- 在 Service 层进行业务校验(例如:促销价不得高于原价)
- 参考:
- 控制器注入与校验:ProductController.php:136-217
- 服务层数据处理:ProductService.php:162-294
商品状态管理(上架/下架/预售)
- 状态字段:status
- 仅上架筛选:scopePublished
- 建议在列表与详情中根据 status 控制可见性与购买入口
- 参考:
- 状态筛选:Product.php:132-141
库存控制
- 字段:stock
- 建议在下单、发货、退货流程中扣减/回滚库存
- 列表展示与校验可在 Service 层加入库存阈值提示
价格管理
- 基础价:price
- 促销价:promote_price
- 会员价:level_price(序列化存储,配合 PricingService 处理)
- 属性值价格变动:attribute_value.price_change(前端累加)
- 参考:
- 会员价处理:ProductService.php:182-185
- 属性值价格变动:AttributeService.php:232-267
批量导入导出
- 导入
- 建议采用 CSV/Excel 解析,分批插入并使用事务保证一致性
- 对关键字段(标题、分类、价格、库存)做校验与去重
- 导出
- 使用分页游标拉取数据,避免一次性加载
- 将图片 URL 转为可下载链接或仅导出文件名
数据同步与缓存策略
- 分类树、品牌列表等低频变更数据可缓存
- 商品详情可按 id 缓存,失效策略:编辑/删除时主动清除
- 缩略图与附件走独立存储盘,便于 CDN 与备份