应采用双层协同架构:状态机作为守门人确保流转合规,工作流引擎作为执行者响应事件完成异步动作、日志归档与多系统集成,实现高可维护性与可扩展性。

如果您在ThinkPHP6.x项目中需要构建可维护、可扩展的业务审批流程,却面临状态散落、条件耦合、流转不可审计等问题,则很可能是缺乏分层的工作流与状态机协同机制。以下是针对该场景的多种设计实现路径:
一、基于状态机的核心流转控制
该方法将实体生命周期严格约束在有限、预定义的状态集合内,仅允许合法状态转移,杜绝非法跳转导致的数据不一致。状态变更不触发副作用,仅抛出领域事件供后续处理。
1、定义枚举类OrderStatus,包含draft、submitted、approved、fulfilled、rejected、cancelled等值。
2、在订单模型Order.php中封装transitionTo()方法,内部校验当前状态与目标状态是否存在于预设的合法转移表中。
3、当校验通过,更新数据库status字段,并使用ThinkPHP事件系统触发OrderStatusChanged事件。
4、监听该事件的处理器(如SendApprovalNotificationListener)负责发送通知,不参与状态判断逻辑。
二、基于责任链模式的审批节点编排
该方法将审批职责解耦为多个独立Handler,每个Handler只响应自身可处理的条件,支持动态配置顺序与策略跳过,避免Controller堆积if-else分支。
1、定义统一接口ApproveHandlerInterface,声明canHandle()和handle()两个方法。
2、创建具体Handler类,例如DepartmentHeadHandler检查$context['dept_head_sign'] === true,FinanceHandler依据$context['amount']执行金额阈值判断。
3、在config/approval_chain.php中声明执行顺序:['DepartmentHeadHandler', 'FinanceHandler', 'AdminHandler']。
4、由ApprovalService读取配置并实例化Handler链,以共享$context对象逐级传递审批结果与错误信息。
三、基于低代码流程引擎的可视化建模
该方法通过JSON结构描述流程图,配合运行时解析器驱动节点执行,使非开发人员可直接调整审批路径,无需修改PHP源码。
1、在数据库tp_flow表中插入一条流程记录,process_json字段存入BPMN简化结构,含nodes与edges数组。
2、定义WorkflowExecutor类,遍历nodes,根据当前节点type调用对应执行器(如UserTaskExecutor处理人工任务)。
3、对含condition字段的节点(如财务审批),使用eval()或轻量表达式引擎解析"amount > 10000"并返回布尔结果。
4、每次流转后,向tp_step表写入新步骤记录,包含flow_id、handler_id、status与handle_time。
四、双层协同架构:状态机+工作流引擎联动
该方法将状态机作为“守门人”,工作流引擎作为“执行者”,前者确保流转合规性,后者响应事件完成异步动作、日志归档与多系统集成。
1、当订单从submitted转为approved,状态机抛出OrderApprovedEvent。
2、工作流引擎监听该事件,根据business_type(如PURCHASE_ORDER)查出已激活的流程定义process_code = 'po_approval_v2'。
3、创建工作流实例,初始化第一个任务节点dept_manager,并写入待办表wf_task。
4、用户在审批中心处理任务时,调用WorkflowService::completeTask($taskId, $result),引擎自动校验当前节点、更新实例状态、触发下一流程边的条件判断。
五、基于数据库驱动的轻量流程持久化方案
该方法不引入外部引擎依赖,完全使用ThinkPHP6.x原生ORM与事务机制管理流程状态,适用于中低复杂度且强调部署简洁性的场景。
1、新建两张表:tp_flow(主键id、name、module_code、version、is_active)与tp_step(flow_id、step_name、assignee_type、assignee_value、sort_order、condition_expr)。
2、提交审批请求时,FlowService根据module_code和version查出启用的步骤列表,并按sort_order排序。
3、遍历步骤列表,对每个步骤执行Db::raw($condition_expr)动态计算是否应跳过或进入该节点。
4、将当前步骤写入tp_instance_step表,标记status = 'pending',同时开启数据库事务包裹整个初始化过程。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











