A-A+

工作流设计参考

2018年09月03日 php 暂无评论 阅读 1,990 views 次

工作流很少有让人满意的,即便是国内用的比较多的jbpm,用起来也会觉得很便扭。再加上PHP中没有什么好用的工作流,于是干脆自己设计一个,设计的原则如下:

1 根据80/20原则,只使用wfmc模型中最符合自身应用的20%功能

2 充分吸收国内使用jbpm开发BOSS中遇到的问题,工作流引擎只负责参数的收集和流程的流转,具体和业务的控制,交给每个流程定制的控制类去实现。

3 表单采用简单的html+控制标签的方法实现

4 权限和模板引擎,以及其它辅助函数直接使用办公系统自带的框架

5 充分利用PHP语言的特点,流程设计是基于数据库的,程序上使用OO设计,但采用重对象的方法

6 不把可视化设计流程的工作交给最终客户,而且由设计时完成,因此不考虑流程版本更新的问题

 

一、工作流数据表设计

 

tbl_workflow_defination:工作流定义表

defination_id 流程id
defination_name 流程名称
defination_handler 流程处理辅助文件,每个工作流一个文件 自定义处理文件,及其对象。例如workflow-proporsal-handler.php,其中定义对象proposal

 

tbl_workflow_node:流程结点步骤表

node_id 结点id
defination_id 流程id
node_index 结点序号 结点的step
node_name 结点名称
node_type 结点类型 1人为决策,2自动处理(直接执行execute_function),3等待外部响应(例如外部WS触发),4分支,5汇总 6结束结点(此结点执行时候自动终止进程)
init_function 流程初始函数
run_function 流程运行函数
save_function 流程保存函数
transit_function 流程流转函数
prev_node_index 前结点序号 例如1。开始结点没有

执行前,通过此来校验一下流程

next_node_index 后结点序号 例如[同意]3,[不同意]4。尾结点或要结束的结点没有,若没有,直接调用end
executor 执行角色,组,人 role[1,2] group[1,2] user[1,2],为空由运行时决定
execute_type 执行类型 0需所有人执行 1只需一人执行
remind 提醒 0不提醒 1邮件 2短信 3邮件和短信
field 可编辑的字段 name,content
max_day 最长时间(天)

 

tbl_workflow_process :流程执行进程表

process_id 进程id
defination_id 流程id
process_desc 进程描述 显示在我的工作台中
context 上下文 存放上下文变量,例如业务表的id
current_node_index 当前结点序号
start_time 流程启动时间 如遇分支、汇合显示为:

1=》3,4=》3,5=》6

finish_time 流程完成时间
state 状态 1运行 2结束
start_user 发起人 发起人,用于显示自己的流程

 

tbl_workflow_thread :流程执行线程表

thread_id 线程id
process_id 进程id
process_desc 进程描述
node_id 结点id
node_name 结点名称
executor 执行人
start_time 线程生成时间
receive_time 线程接收时间
finish_time 线程完成时间
max_time 结点规定的最长时间
state 状态 0未接收 1已接收 2已处理

 

二、常见流程

人工决策

 

领导传阅

部门领导审批

填写表单
结束
放弃
提交
同意
重填(退回)
不同意
完成

 

外部响应

 

发送支付信息

接收支付成功响应(外部WS触发该流程)

 

三、PHP设计

运行的函数由结点在设计时候决定,如果没有设定,就使用默认的函数。利用了PHP语言的以下特性

<?php
class Foo
{
    function Variable()
    {
        $name 'Bar';
        $this->$name(); // This calls the Bar() method
    }
    
    function Bar()
    {
        echo "This is Bar";
    }
}

$foo = new Foo();
$funcname "Variable";
$foo->$funcname();  // This calls $foo->Variable()

?>

使用前可以用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)

 

 

 

转载自:小伢子

标签:

给我留言