Zend - The PHP Company




Utilities

Add Code


Workflow engine  

Type: code fragment
Added by: aristo
Entered: 17/05/2005
Last modified: 02/12/2005
Rating: - (fewer than 3 votes)
Views: 7156
Simple busines workflow engine. You can code own business jobs (workflow steps), and embed it to workflow engine. Big advatage is that you change workflow you don't need to recode anything - only change configuration of workflow.


<!-- Create tables -->
<!-- 
------------------------------------------------
////////////////////////////////////////////////
//
//    WORKFLOW definition:
//        wf_id:             uniform workflow ID - 1..N
//        wf_name:         workflow name identifier - Loans
//        wf_desc:         description of workflow - This worklflow provides loan process for Corporate clients
//        wf_app:         appliacation identifier - 1..N (1st group level - There can be stored workflow which are used by many applications - application is identified by integer value 1..N)
//        wf_type:         type of workflow under any application - 1..N (2nd group level - Identification the type of workflow within the application)
//        validfrom:         datetime value FROM which is workflow accessible
//        validto:        datetime value TO which if workflow accessible 
//
////////////////////////////////////////////////
CREATE TABLE `wf_desc` (
  `wf_id` tinyint(4) NOT NULL auto_increment,
  `wf_name` varchar(50) default NULL,
  `wf_desc` text,
  `wf_app` int(11) default NULL,
  `wf_typ` int(11) default NULL,
  `validfrom` datetime default NULL,
  `validto` datetime default NULL,
  PRIMARY KEY  (`wf_id`),
  UNIQUE KEY `wf_id` (`wf_id`)
) TYPE=MyISAM
------------------------------------------------
////////////////////////////////////////////////
//
//    This table defines structure of workflows:
//        wf_id:             workflow ID - 1..N (relation to with wf_desc.wf_id)
//        step_id:        uniform JOB ID - 1..N
//        step_source:    source code of the JOB - increment.php
//        
////////////////////////////////////////////////
CREATE TABLE `wf_def` (
  `wf_id` int(11) NOT NULL default '0',
  `step_id` int(11) NOT NULL default '0',
  `step_source` varchar(50) default NULL,
  PRIMARY KEY  (`wf_id`,`step_id`)
) TYPE=MyISAM
------------------------------------------------
////////////////////////////////////////////////
//
//    This Table store actual status of each run workflow:
//        id:                uniform activ workflow ID - 1..N
//        wf_id:             workflow ID - 1..N (relation to with wf_desc.wf_id)
//        current_step:    identifier of actual step in this workflow
//        dtime_start:    datetime value when workflow started
//        dtime_chng:        datetime value of the last change in workflow
//        wf_owner:         indentifier of the owner. 
//                        Owner is person whoes started workflow. 
//                        This value can by interconnected with autorization module (auth. module is not describe here).
//                        If there is not auth. module value of this field is "0" (zero) 
//        param:            parameters of workflow.
//                        Value is stored in HTTP-GET convention in rawurlencoded format:
//                            a=1&b=22&name=jano.. - a%3D1%26b%3D22%26name%3Djano
//                        This params as input for JOB (sourcecode) represented (see wf_explode()): 
//                            $_WF[a]=1;
//                            $_WF[b]=22;
//                            $_WF[name]=jano;
//                            Each JOB can manage of this values standardly by using of $_WF[xxx]=yyy
//                        Workflow engine builds this value as output values $_WF[xxx] of each JOB. (see wf_implode())
//
////////////////////////////////////////////////
CREATE TABLE `wf_active` (
  `id` int(11) NOT NULL auto_increment,
  `wf_id` int(11) default NULL,
  `current_step` int(11) NOT NULL default '0',
  `dtime_start` datetime default NULL,
  `dtime_chng` datetime default NULL,
  `wf_owner` int(11) default NULL,
  `param` text,
  PRIMARY KEY  (`id`)
) TYPE=MyISAM
------------------------------------------------
-->
<!-- End of create tables -->

<!-- Start 1st upload of the tables -->
<!-- 
// upload 3 workflows
INSERT INTO `wf_desc` (`wf_id`, `wf_name`, `wf_desc`, `wf_app`, `wf_typ`, `validfrom`, `validto`) VALUES 
  (1,'Workflow 1','Inc+Dec+Inc+Inc',1,1,now(),NULL),
  (2,'Workflow 2','Set2nd+Inc+Inc+Inc+Dec+Dec',1,1,now(),NULL),
  (3,'Workflow 3','Inc+Set2nd',1,1,now(),NULL);

// build structure of each workflow
INSERT INTO `wf_def` (`wf_id`, `step_id`, `step_source`) VALUES 
  (1,1,'wf_increm.php'),
  (1,2,'wf_decrem.php'),
  (1,3,'wf_increm.php'),
  (1,4,'wf_increm.php'),
  (2,1,'wf_set2nd.php'),
  (2,2,'wf_increm.php'),
  (2,3,'wf_increm.php'),
  (2,4,'wf_increm.php'),
  (2,5,'wf_decrem.php'),
  (2,6,'wf_decrem.php'),
  (3,1,'wf_increm.php');
  (3,2,'wf_set2nd.php'),
-->
<!-- End 1st upload of the tables -->


<!-- Start of wf.engine.php -->
<?php
if (isset($_POST[param])) {
    
$_GET[param]=rawurlencode($_POST[param]);
}

// -------------
// explode _WF metadata
function wf_explode($meta) {
    if (!empty(
$meta)) {
        
$wftemp=explode("%26"$meta); //divide string according to "&"
        
for ($i=0$i<count($wftemp); $i++) {
            
$wf=explode("%3D"$wftemp[$i]);    //divide each array according to "="
            
$_WF[$wf[0]]=$wf[1];
            
//echo '$_WF['.$wf[0].']='.$wf[1].'<br>';
        
}
        unset(
$wftemp);
        unset(
$wf);
    }
    return 
$_WF;
}

// implode _WF metadata
function wf_implode($wf) {
    
$meta='';
    if (
$wf>0) {
        
$wfnames=array_keys($wf);
        for (
$i=0$i<count($wf); $i++) {
            
$meta=$meta.'&'.$wfnames[$i].'='.$wf[$wfnames[$i]];
        }
    }
    return 
rawurlencode(substr($meta,1));
}
// -------------

if (!isset($_GET[sign]) ) { //praparation for increase security (signing of request) - this will be implemented in future versions
    
if (isset($_GET[wf_start])) {
        
$WF="
            insert into wf_active (wf_id, current_step, dtime_start, dtime_chng, wf_owner, param) 
            values 
                ("".
$_GET[wf_start]."", "".$_GET[wf_step]."", now(), now(), "".$phorum_user[id]."", "".$_GET[param]."")
            "
;
        
//echo $WF;
        
mysql_query($WF);
        
$WFID=mysql_query("SELECT LAST_INSERT_ID() as wf_id");
        
$RWFID=mysql_fetch_array($WFID);
        
$_GET[wf_active]=$RWFID['wf_id'];
        
$_GET[wf_id]=$_GET[wf_start];
    }
    if (isset(
$_GET[wf_active])) {
        
$WF="select step_source from wf_def where wf_id="".$_GET[wf_id]."" AND step_id="".$_GET[wf_step].""";
        
//echo $WF."<br>n";
        
$WF=mysql_query($WF);
        if (
$RWF=mysql_fetch_array($WF)) {
            if (
file_exists($RWF[step_source])) {

                
//$param=explode(";", $_GET[param]);
                
$_WF=wf_explode($_GET[param]); // create $_WF array from PARAM String

                
include $RWF[step_source];

                
$param=wf_implode($_WF); // Rebuild PARAM String from each $_WF 

                
$WFRES="
                    update 
                        wf_active
                    set
                        param="".
$param."", 
                        dtime_chng=now(),
                        current_step="".(
$_GET[wf_step]+1).""
                    where 
                        id=
$_GET[wf_active]
                    "
;
                
//echo $WFRES."<br>n";
                
$WFRES=mysql_query($WFRES);
            } else {
                echo 
"<span class="error">Sourcecode of this JOB <strong>$RWF[step_source]</strong> doesn't exists!</span>";
            }
        }
    }
}
?>
<!-- END OF wf.engine.php -->

<!-- Convetnion for JOB sourcecode writing 
// JOBs can standardly uses external sources (DBs, WEBServices, Other incluede sourcecodes, etc...)
// and still can use parameters sended by previeus JOBs through $_WF arrays using.
// JOBs souldn't be a visual components. They cen write someting to other metadata or DB or GLOBALS, etc.. and visualization should be coded separately.
// In this example JOB manage only $_WF arrays but it is only for example!!! You can code own jobs!!! 
-->
<!-- Start wf_increm.php -->
<?php
//proc start 
if (isset($_WF[a])) {
    
$_WF[a]++;
}
//proc finish
?>
<!-- End wf_increm.php -->

<!-- Start wf_decrem.php -->
<?php
//proc start 
if (isset($_WF[b])) {
    
$_WF[b]--;
}
//proc finish
?>
<!-- End wf_increm.php -->

<!-- Start wf_increm.php -->
<?php
//proc start 
$_WF[b]=50;
$_WF[a]=$_WF[a]+280;
//proc finish
?>
<!-- End wf_increm.php -->


Usage Example


<?php 
$link 
mysql_connect("mysql_host""mysql_user""mysql_password"
    or die(
"It is not possible to connect DB");
mysql_select_db('mysql_database'$link);
?>
<!-- WORKFLOW ENGINE Included to INDEX PAGE -->
<?php include 'wf.engine.php'?>

<html>
<head>
    <title>WORKFLOW ENGINE 0.2</title>
</head>
<style type="text/css">
    body, table, tr, td {
        font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
        font-size: 10px;
    }
    td {
        padding: 0px 2px 0px 2px;
    }
    div {
        margin: 0px 0px 0px 0px;
        padding: 5px 0px 5px 0px;
        border-bottom: 2px dotted Silver;
    }
    .error {
        padding: 0px 5px 0px 5px;
        background-color: Red;
        Color: Yellow;
    }
    table tr td {
        border-right: 1px solid #a0a0a0;
    }
    #r0 {
        background-color: #f5f5f5;
    }
</style>
<body>

<!-- 1st part - small menu :) -->
<div><a href="wf.index.php">REFRESH</a></div>
<!-- 2nd part - workflows for Application number 1 -->
<div>
<?php
$app_num
=1;
$WF=mysql_query("select * from wf_desc where wf_app="$app_num" AND ( validfrom<=now() AND ( validto is Null OR validto>=now() ) )");
while (
$RWF=mysql_fetch_array($WF)) {
?>
    <form action="?wf_start=<?=$RWF[wf_id]?>&wf_step=1" method="post" name="wf_<?=$RWF[wf_id]?>">
        <?=$RWF[wf_id]?> <strong><?=$RWF[wf_name]?></strong> 
        <input type="Text" name="param">
        <?=$RWF[wf_desc]?>
        <a href="javascript:document.wf_<?=$RWF[wf_id]?>.submit()">START</a><br>
    </form>
<?php
}
?>
</div>
<!-- 3rd part - active workflow -->
<div>
<table width="100%" cellpadding="0" cellspacing="0">
<?php
$WF
="select *, (dtime_chng-dtime_start) as dif from wf_active order by id desc limit 10";
$WF=mysql_query($WF);
$row=1;
while (
$RWF=mysql_fetch_array($WF)) {
?>
    <tr onmouseout="javascript:style.backgroundColor=''" onmouseover="javascript:style.backgroundColor='#e5e5e5'" <?php if($row==0) {?>id="r0"<?php $row=1; } else { $row=0;}?>>
        <td><?=$RWF[id]?></td>
        <td><?=$RWF[wf_id]?></td>
        <td><?=$RWF[current_step]?></td>
        <td><?=$RWF[wf_owner]?></td>
        <td><?=$RWF[dtime_start]?></td>
        <td><?=$RWF[dtime_chng]?></td>
        <td><?=$RWF[dif]?></td>
        <td><?=rawurldecode($RWF[param])?></td>
        <td align="right">
            <?php 
            $WFCH
=mysql_query("select max(step_id) as sum_steps from wf_def where wf_id="".$RWF[wf_id].""");
            
$RWFCH=mysql_fetch_array($WFCH);
            if (
$RWFCH[sum_steps]>=$RWF[current_step]) {
            
?>
                <a href="?wf_active=<?=$RWF[id]?>&wf_id=<?=$RWF[wf_id]?>&wf_step=<?=$RWF[current_step]?>&param=<?=rawurlencode($RWF[param])?>">NEXT</a>
            <?php 
            
} else {
            
?>
                FINISH
            <?php 
            
}
            
?>
        </td>
    </tr>
    <?php
}
?>
</table>
</div>

</body>
</html>
<?
mysql_close
($link);
?>


Rate This Script





Search



This Category All Categories