工作流设计参考(包括PHP实现)

工作流很少有让人满意的,即便是国内用的比较多的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)

参考文献:

https://www.ctolib.com/topics-81696.html

猜你喜欢

转载自blog.csdn.net/weixin_41282397/article/details/83513253