工作流很少有让人满意的,即便是国内用的比较多的jbpm,用起来也会觉得很便扭。再加上PHP中没有什么好用的工作流,于是干脆自己设计一个,设计的原则如下: 1 根据80/20原则,只使用wfmc模型中最符合自身应用的20%功能 2 充分吸收国内使用jbpm开发BOSS中遇到的问题,工作流引擎只负责参数的收集和流程的流转,具体和业务的控制,交给每个流程定制的控制类去实现。 3 表单采用简单的html+控制标签的方法实现 4 权限和模板引擎,以及其它辅助函数直接使用办公系统自带的框架 5 充分利用PHP语言的特点,流程设计是基于数据库的,程序上使用OO设计,但采用重对象的方法 6 不把可视化设计流程的工作交给最终客户,而且由设计时完成,因此不考虑流程版本更新的问题 一、工作流数据表设计 tbl_workflow_defination:工作流定义表
tbl_workflow_node:流程结点步骤表
tbl_workflow_process :流程执行进程表
tbl_workflow_thread :流程执行线程表
二、常见流程 人工决策
运行的函数由结点在设计时候决定,如果没有设定,就使用默认的函数。利用了PHP语言的以下特性
使用前可以用method_exists来检查。
WorkflowService.php WorkflowService $defination $process $node $thread $input 用户输入的和流程有关的变量 list_defination() { } init_process(defination_id) { global user; 取得$defination,得到业务的handler,例如WorkflowProposalHandler 建立$process行记录 } start_process() { 调用WorkflowProposalHandler->start($process)//新建业务对象,并把业务类的参数例如proposal_id放到$process['context’]里面 init_thread(1); //默认调用第一个结点 }
list_ my_thread () { global user; }
init_thread(node_index) { 取得$node 取得$process 修改$process为运行到当前结点 Switch($node['node_type’]) Case 1: 人工决策 建立$thread WorkflowProposalHandler-> init_function ($process,$node,$thread) 发送提醒 Case 2: 自动处理 建立$thread WorkflowProposalHandler-> init_function ($process,$node,$thread) 调用run_thread(thread_id) Case 3: 等待外部响应 建立$thread WorkflowProposalHandler-> init_function ($process,$node,$thread) Case 4: 分支 取得所有分支的子结点 init_thread(子结点) Case 5: 汇总: 取得所有前结点,如果所有前结点的Thread都结束了,调出下一结点 调用init_thread(子结点) Case 6: 结束:直接结束进程process end_process() } run_thread(thread_id) { 取得$node 取得$process 取得$thread Switch($node['node_type’]) Case 1: 人工决策 修改$thread为已接收 WorkflowProposalHandler-> run_function ($process,$node,$thread) 显示表单 Case 2: 自动处理 修改$thread为已接收 $next_node_id=WorkflowProposalHandler-> run_function ($process,$node,$thread) 调用transit_thread(thread_id, $next_node_id) Case 3: 等待外部响应 修改$thread为已接收 $next_node_id=WorkflowProposalHandler-> run_function ($process,$node,$thread) transit_thread(thread_id, $next_node_id) Case 4: 分支 Case 5: 汇总: Case 6: 结束: } save_thread(thread_id) { //保存结点数据 取得$node 取得$process 取得$thread Switch($node['node_type’]) Case 1: 人工决策 WorkflowProposalHandler-> save_function ($process,$node,$thread) 保存表单 WorkflowProposalHandler-> run_function ($process,$node,$thread) 显示表单 Case 2: 自动处理 Case 3: 等待外部响应 Case 4: 分支 Case 5: 汇总: Case 6: 结束: } transit_thread(thread_id, $next_node_id) { 取得$node 取得$process 取得$thread Switch($node['node_type’]) Case 1: 人工决策 WorkflowProposalHandler->transit_function($process,$node,$thread,$next_node_id) 修改$thread为已完成 If($next_node_id < $ cur_node_id) { //回退 删除所有大于$next_node_id的Thread } init_thread($next_node_id) Case 2: 自动处理 修改$thread为已完成 If($next_node_id < $ cur_node_id) { //回退 删除所有大于$next_node_id的Thread } init _thread($next_node_id) Case 3: 等待外部响应 修改$thread为已完成 If($next_node_id < $ cur_node_id) { //回退 删除所有大于$next_node_id的Thread } init _thread($next_node_id) Case 4: 分支 Case 5: 汇总: Case 6: 结束:
}
end_process()
list_my_process view_process
workflow_proposal_handler.php WorkflowProposalHandler start() prepare_input() 准备用户输入变量,从$_POST收集 init_function () 线程建立后调用的默认函数,当流程的执行者由程序生成时,在此函数内更改$thread的executor,例如直接赋值user[2] run_function () 线程运行化时候调用的默认函数 save_function () 保存运行信息 transit_function () 执行流转 sendmail 其它结点调用函数
workflow.php switch(op) case list_defination 参数:无 WorkflowService->list_defination() case start_process : 启动 参数:defination_id WorkflowService->init_process(defination_id) WorkflowService->start_process() case list_ my_thread : 待处理的列表 WorkflowService->list_ my_thread() case run_thread : 参数:thread_id WorkflowService->run_thread(thread_id) case save_thread : 参数:thread_id 把input收集起来(所有的变量以 f_ 开头),赋给WorkflowService的Input,另外还要获得thread_id WorkflowService->save_thread(thread_id) case transit_thread : 参数:thread_id 把input收集起来,赋给WorkflowService的Input,另外还要获得thread_id $next_node_id = 得到用户选择的下一结点id WorkflowService-> transit _thread(thread_id,$next_node_id)
case list_my_process: 所有我发起的流程 case list_all_process: 所有我发起的流程 case view_process : 在其它程序中初始化流程 1先自行建立好业务表单 2WorkflowService->init_process(defination_id) 3把建好的业务表单的ID放在process的context里面 4WorkflowService->init_thread(1) WorkflowService->transit_thread(1,2) 通过手动调用把前面的流程过掉 外部服务继续流转流程(只用于自动流程) 1 把input收集起来,赋给WorkflowService的Input,另外还要获得thread_id 2 WorkflowService->run_thread(thread_id) |
|