天天看點

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