1. 程式人生 > >工作流設計參考(包括PHP實現)

工作流設計參考(包括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