Symfony电商系统以状态流转、数据一致性和异步解耦为核心:商品模块用实体校验+行锁防超卖;订单模块依托Workflow管理状态机;支付模块将回调转为事件驱动;命令总线统一调度业务动作。

用 Symfony 搭建电商系统,商品、订单、支付三个模块不是孤立开发的,而要围绕状态流转、数据一致性与异步解耦来组织。核心不在于写多少代码,而在于关键节点是否受控。
商品模块:用实体+校验+API驱动库存可见性
商品不是静态信息容器。在 Symfony 中,Product 实体需包含 price、stock、availability(是否可售)等字段,并配合 Doctrine Lifecycle Callback 或自定义仓储方法,在保存前校验库存逻辑是否合理。例如,当 stock 为 0 且 availability 仍为 true,应自动置为 false。
对外暴露的 API(如 /api/products/{id})必须返回实时库存状态,不能缓存过期值。推荐使用 Doctrine 的 SELECT ... FOR UPDATE 在扣减前锁定行,避免超卖。
- 商品列表接口默认按 visibility 和 stock 排序,隐藏已下架或无库存项
- 前端添加到购物车时,先调用
/api/products/{id}/check-availability验证,再执行添加 - 图片上传走独立 endpoint(如
/api/products/{id}/media),用 VichUploaderBundle 管理文件与实体绑定
订单模块:靠 Workflow 管理状态,拒绝布尔字段硬编码
不要用 is_paid、is_shipped 这类字段。Symfony/Workflow 是唯一可靠的状态控制方式。定义明确状态机:
cart → confirmed → payment_pending → paid → shipped → completed
每个 transition 绑定 guard,比如 payment_pending 要求库存锁定成功、价格未变动;paid 要求支付回调已验证且幂等通过。
- Order 实体只存一个
state字符串字段和快照字段(如snapshot_price、snapshot_stock_version) - 创建订单时触发
confirm_ordertransition,自动扣减库存并生成唯一out_trade_no - 所有状态变更必须包裹在 Doctrine 事务中,失败则全部回滚
支付模块:回调即事件,不处理业务,只推动状态
支付网关(微信/支付宝/Stripe)只是外部黑盒。你的系统只做三件事:生成支付凭据、接收通知、更新状态。
回调入口(如 /webhook/wechat)必须满足:
- 签名验证通过后,立即查库确认该
out_trade_no是否已处理,重复请求直接返回 200 - 仅调用
$workflow->apply($order, 'confirm_payment'),不发短信、不调发货、不更新物流 - 后续动作(如通知用户、同步发票、触发发货)由监听
PaymentConfirmedEvent的 MessageBus handler 异步完成
前端调起支付前,先通过 API 创建 PaymentIntent 并关联 Order,把 client_secret 返回给前端,由 Stripe.js 完成收银台渲染。
命令总线:把“做什么”和“怎么做”彻底分开
Symfony Messenger 不是锦上添花,而是必须启用的基础设施。所有耗时、跨服务、需重试的操作都应封装为 Command。
-
CreateOrderCommand:含 cartId、userId,交由 handler 创建订单并校验库存 -
SendInvoiceCommand:在paid状态后由 event listener 分发,调用 FakturowniaBundle 发票服务 -
SyncStockToERPCommand:成功发货后触发,异步推送到内部 ERP 系统
命令默认同步执行,但配置 async: amqp 后,自动进入 RabbitMQ 或 Redis 队列,失败可重试、可监控、可延迟。

















