工作流设计参考(包括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语言的以下特性
|
使用前可以用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)
工作流设计参考(包括PHP实现)的更多相关文章
- Winform开发框架之简易工作流设计
一讲到工作流,很多人第一反应就是这个东西很深奥,有时候又觉得离我们较为遥远,确实完善的工作流设计很多方面,而正是由于需要兼顾很多方面,一般通用的工作流都难做到尽善尽美.微软也提供了几个版本的WF框架支 ...
- 工作流设计 zt
工作流设计 业务流程管理模块是本平台的重要组成部分,要实现将已经发布的标准中规范化的流程转化为具体计算机中的流程从而实现流程的自动运转,将标准化成果与员工的日常工作紧密结合起来,具有重要意义. 业务流 ...
- 构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(43)-工作流设计-字段分类设计
原文:构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(43)-工作流设计-字段分类设计 系列目录 建立好42节的表之后,每个字段英文表示都是有意义的说明.先建立 ...
- UED团队规范设计参考及建议
公司产品线逐渐增多,变动频繁且并行开发,常常需要设计与开发能够快速的做出响应.同时这类产品中有存在很多类似的页面以及组件,可以通过抽象得到一些稳定且高复用性的内容.通过模块化的解决方案,降低冗余的生产 ...
- Winform开发框架之简易工作流设计(转自 伍华聪博客)
Winform开发框架之简易工作流设计 一讲到工作流,很多人第一反应就是这个东西很深奥,有时候又觉得离我们较为遥远,确实完善的工作流设计很多方面,而正是由于需要兼顾很多方面,一般通用的工作流都难做到尽 ...
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(42)-工作流设计-表建立
系列目录 工作流在实际应用中还是比较广泛,网络中存在很多工作流的图形化插件,可以做到拉拽的工作流设计,非常简便,再配合第三方编辑器,可以直接生成表单,我没有刻意的浏览很多工作流的实际设计,我认为工作流 ...
- 构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(48)-工作流设计-起草新申请
原文:构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(48)-工作流设计-起草新申请 系列目录 创建新表单之后,我们就可以起草申请了,申请按照严格的表单步骤和分 ...
- 构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(47)-工作流设计-补充
原文:构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(47)-工作流设计-补充 系列目录 补充一下,有人要表单的代码,这个用代码生成器生成表Flow_Form表 ...
- 构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(46)-工作流设计-设计分支
原文:构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(46)-工作流设计-设计分支 系列目录 步骤设置完毕之后,就要设置好流转了,比如财务申请大于50000元( ...
随机推荐
- 小牟Andorid下面MD5具体实现的思路总结
Android的开发往往需要一定数目demo 从今起MD5一些加密算法提取物 看看是如何实现的 首先,我们必须明确为什么加密? 1 数据安全处理 2 防止数据窃取 3 有效的避免恶意攻击 4 保证文件 ...
- 【蓝桥杯】 PREV-1 核桃数
主题链接:http://lx.lanqiao.org/problem.page?gpid=T24 历届试题 核桃的数量 时间限制:1.0s 内存限制:256.0MB 问题描写 ...
- 基于最简单的FFmpeg采样读取内存读写:内存玩家
===================================================== 基于最简单的FFmpeg样品系列读写内存列表: 最简单的基于FFmpeg的内存读写的样例:内 ...
- android利用jdk制作签名
Apk签名首先要有一个keystore的签名用的文件. keystore是由jdk自带的工具keytool生成的.详细生成方式參考一下: 開始->执行->cmd->cd 到你安装的j ...
- 它的斗争“和loser对话”短篇故事
今天,一个朋友发来的图片故事,尽管听说过,但见一.仍感慨颇多. 有时总是说easy,其实做起来的另一个故事. 想实现梦想,看来还是要脚踏实地,一步一步.不断努力,不断前行啊! 版权声明:本文博客原创文 ...
- 【SSH2(理论+实践)】--Hibernate步步(一个)
前几个博客讨论SSH2该框架Struts,它代表层,集成封装.和使用WebWork作为核心处理,依赖映射是它的处理核心.在使用时需要Struts.xml配置相应Action和Interceptor够完 ...
- HDU 3853 LOOPS 可能性dp(水
在拐~ #include <stdio.h> #include <cstring> #include <iostream> #include <map> ...
- 联想G480安装CentOS电缆驱动器
最近.联想G480 32本机安装现场CentOS 6.5. 发现.总是无法使用有线网络. 必须安装必要的驱动,搜集了资料,安装过程例如以下: 1. 必备的软件 安装前,须要下列的软件依赖包. sudo ...
- JavaWeb框架的基石
JavaWeb框架的基石(一) 初学JavaWeb开发,请远离各种框架,从Servlet开始. Web框架是开发者在使用某种语言编写Web应用服务端是关于架构的最佳实践.很多Web框架 ...
- UVA1232 - SKYLINE(段树部分的变化)
UVA1232 - SKYLINE(线段树区间改动) 题目链接 题目大意:依照顺序盖楼.假设这个位置(当前要盖的楼覆盖范围内)要新建的楼的高度>=之前就有的最大高度,那么就+1.最后输出这个+1 ...