• 工作流设计参考(包括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_idThread

    }

    init_thread($next_node_id)

    Case 2: 自动处理

    修改$thread为已完成

               If($next_node_id < $ cur_node_id) { //回退

    删除所有大于$next_node_idThread

    }

           init _thread($next_node_id)

    Case 3: 等待外部响应

        修改$thread为已完成

               If($next_node_id < $ cur_node_id) { //回退

    删除所有大于$next_node_idThread

    }

        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 () 线程建立后调用的默认函数,当流程的执行者由程序生成时,在此函数内更改$threadexecutor,例如直接赋值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_ 开头),赋给WorkflowServiceInput,另外还要获得thread_id

        WorkflowService->save_thread(thread_id)

       case transit_thread :

       参数:thread_id

    input收集起来,赋给WorkflowServiceInput,另外还要获得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放在processcontext里面

    4WorkflowService->init_thread(1)

    WorkflowService->transit_thread(12) 通过手动调用把前面的流程过掉

    外部服务继续流转流程(只用于自动流程)

    input收集起来,赋给WorkflowServiceInput,另外还要获得thread_id

    2 WorkflowService->run_thread(thread_id)

  • 相关阅读:
    [java]java String.split()函数的用法分析
    [sql]java.sql.Types的具体对应值(jdbcType)
    [sql]join的5种方式:inner join、left(outer) join、right (outer) Join、full(outer) join、cross join
    [java]String和Date、Timestamp之间的转换
    [Eclipse]保存java文件时,自动删除不需要的包import
    [postgresql]ROWS is not applicable when function does not return a set问题解决
    [postgreSql]postgreSql数据库、模式、表、函数的删除与创建
    zbb20170816 oracle Oracle 查看表空间、数据文件的大小及使用情况sql语句
    zbb20170811 mysql远程连接报错: Host * is not allowed to connect to this MySQL server,解决方法
    zbb20170811 linux 给用户授予文件夹权限
  • 原文地址:https://www.cnblogs.com/baocheng/p/5778869.html
Copyright © 2020-2023  润新知