工做流不多有讓人滿意的,即使是國內用的比較多的jbpm,用起來也會以爲很便扭。再加上PHP中沒有什麼好用的工做流,因而乾脆本身設計一個,設計的原則以下:php
1 根據80/20原則,只使用wfmc模型中最符合自身應用的20%功能html
2 充分吸取國內使用jbpm開發BOSS中遇到的問題,工做流引擎只負責參數的收集和流程的流轉,具體和業務的控制,交給每一個流程定製的控制類去實現。node
3 表單採用簡單的html+控制標籤的方法實現數據庫
4 權限和模板引擎,以及其它輔助函數直接使用辦公系統自帶的框架框架
5 充分利用PHP語言的特色,流程設計是基於數據庫的,程序上使用OO設計,但採用重對象的方法函數
6 不把可視化設計流程的工做交給最終客戶,並且由設計時完成,所以不考慮流程版本更新的問題this
1、工做流數據表設計spa
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已處理 |
2、常見流程
人工決策
領導傳閱 |
部門領導審批 |
填寫表單 |
結束 |
放棄 |
提交 |
贊成 |
重填(退回) |
不一樣意 |
完成 |
外部響應
發送支付信息 |
接收支付成功響應(外部WS觸發該流程) |
3、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)