Rapid Application Development toolkit for building Administrative Web Applications

An Activity Based Workflow Engine for PHP

By Tony Marston

16th September 2004
Amended 1st Nov 2016

As of 10th April 2006 the software discussed in this article can be downloaded from www.radicore.org

Introduction
Workflow modelling with Petri Nets
Objects within a Petri Net
Triggers within a Petri Net
Routing within a Petri Net
Splitting and Joining within a Petri Net
A sample Workflow process
Database Design
Workflow E-R Diagram
WORKFLOW table
PLACE table
TRANSITION table
ARC table
CASE table
TOKEN table
WORKITEM table
Maintenance Screens
Processes
Places
Transitions
Arcs
Cases
Tokens
Workitems
The Workflow Engine
Creating a new workflow Case
Updating an existing workflow Case
Result of Creating a Token
Running batch tasks with AUTO triggers
Conclusion
Frequently Asked Questions (FAQ)
References
Amendment History

Introduction

A computer application contains a number of different 'tasks', 'transactions', 'programs' or 'modules', each of which performs a particular function. Sometimes the processing of one particular task is supposed to be followed by one or more other tasks in order to complete some higher process. For example, the task 'Take Customer Order' may have to be followed by 'Charge Customer', 'Pack Order' and 'Ship Order'. This higher process may have a name such as 'Order Fulfillment', but as you can see it cannot be handled by a single task and has to be broken down into its component parts.

Without a workflow system the processing of the component parts has to be handled manually, which is where mistakes can occur. Forgetting to charge the customer or ship the order is not a good way to run a business.

With a Workflow system it is possible to define 'Order Fulfillment' as a workflow process, with 'Charge Customer', 'Pack Order' and 'Ship Order' as components of that process. When an instance (or 'case') of the workflow process is created the workflow engine will then take responsibility for dealing with each component in turn. These components may be executed automatically, or they may be directed to appear in someone's inbox.

What is a 'workflow' system? The Workflow Management Coalition defines 'workflow' as:

The automation of a business process, in whole or part, during which documents, information or tasks are passed from one participant to another for action, according to a set of procedural rules.

There can be two basic types of workflow:

This document will describe the activity based workflow system which I have constructed as an extension to my Development Infrastructure for PHP. This workflow system has the following component parts:


Workflow Modelling with Petri Nets

In order to implement a workflow system it is first necessary to find a suitable means of designing and modeling a workflow process. For this I take advantage of the work done by Carl Adam Petri who was the first to formulate a general theory for discrete parallel systems which gave birth to what are now known as Petri Nets.

Petri Nets is a formal and graphical language which is appropriate for modelling systems with concurrency and resource sharing. It is a generalisation of automata theory such that the concept of concurrently occurring events can be expressed.

Petri Nets have become so popular and widespread that there is a Platform Independent PetriNet Editor (PIPE) available, and it even has its own Petri Net Markup Language (PNML).

Objects within a Petri Net

The Petri Net language contains the following basic objects:

Places These are inactive and are analogous to inboxes in an office-based system. They are shown as circles in a Petri Net diagram. Each Petri Net has one start place and one end place, but any number of intermediate places.
Transitions These are active and represent tasks to be performed. They are shown as rectangles in a Petri Net diagram.
Arcs Each of these joins a single Place to a single Transition. They are shown as connecting lines in a Petri Net diagram. An inward arc goes from a Place to a Transition and an outward arc goes from a Transition to a Place.
Tokens These represent the current state of a workflow process. They are shown as black dots within Places in a Petri Net diagram. A place can hold zero or more tokens at any moment in time.

These objects are subject to the following rules:

Triggers within a Petri Net

The time the transition is enabled and the time it fires are different. The thing that causes an enabled transition to fire is called a trigger. There are four different types of trigger:

workflow-auto-trigger (1K) Automatic A task is triggered the moment it is enabled instead of being placed in a queue.
workflow-user-trigger (1K) User A task is triggered by a human participant, i.e., a user selects an enabled task instance to be executed. In a workflow management system each user has a so-called 'in-basket'. This in-basket, which will be displayed on the Menu/Home Page, contains task instances (workitems) that are enabled and may be executed by the user. By selecting and completing a workitem the corresponding task instance is triggered and the workflow case is advanced to the next stage in the process.
workflow-time-trigger (1K) Time An enabled task instance is triggered by a clock, i.e., the task is executed when a predefined deadline is passed. For example, the task 'remove document' is triggered if a case is trapped in a specific state for more than 15 hours.

This should be one of the options in an implicit OR split.

Because this type of task can be triggered by a background process which runs at scheduled times it cannot have any dialog with the user. It is also possible to use an online screen to view timed events which have passed their deadline, from where individual workitems can be selected and triggered manually.

workflow-msg-trigger (1K) Message An external event (i.e. a message) triggers an enabled task instance. Examples of messages are telephone-calls, fax messages, e-mails or EDI messages.

Each of these external events will probably require some action within an application task so that the workflow system is made aware that the event has taken place.

Routing within a Petri Net

The route between the start place and the end place within a workflow process can take several forms. These are:

Sequential Routing

workflow-seq-routing (1K)

Parallel Routing

workflow-parallel-routing (3K)

Conditional Routing

workflow-conditional-routing (3K)

Iterative Routing

workflow-iterative-routing (3K)

Splitting and Joining within a Petri Net

In order implement these routings you may employ a selection of splits and joins. These are:

AND split
workflow-and-split (1K) An example of parallel routing where several tasks are performed in parallel or in no particular order. It is modeled by a transition with one input place and two or more output places. When fired the transition will create tokens in all output places.
AND join
workflow-and-join (1K) A transition with two or more input places and one output place. This will only be enabled once there is a token in all of the input places, which would be after each parallel thread of execution has finished.
Explicit OR split
workflow-explicit-or-split (1K) An example of conditional routing where the decision is made as early as possible. It is modeled by attaching conditions or guards to the arcs going out of a transition to different places.

Guard - An expression attached to an arc, shown in brackets, that evaluates to either TRUE or FALSE. Tokens can only travel over arcs when their guard evaluates to TRUE. The expression will typically involve the case attributes.

More than two arcs of this type can come out of the same transition. They must all have a condition except the last arc as this will be used as the default path if none of the other conditions evaluates to TRUE.

Implicit OR split
workflow-implicit-or-split (1K) An example of conditional routing where the decision is made as late as possible. Implicit or-splits are modeled as two or more arcs going from the same place but to different transitions. That way, the transition that happens to fire first will get the token. Once the token is gone, the remaining transitions are cancelled and thus cannot be fired.

One of the transitions may have a timer as its trigger so that it will be fired if none of the other transitions is activated before the time limit expires. Expired transitions can either be triggered automatically via a background process which is running on a timer (e.g. cron), or manually via an online screen.

OR join (explicit and implicit)
workflow-or-join (1K) Is simply a place that serves as the output place of two different transitions. That way, the next transition after the or-join place will be enabled when either of the two conditional threads are done.


A sample Workflow process

A workflow is the formal definition of the process used to manage cases of a specific kind (e.g. order fulfillment, article publishing). Each kind of case will have its own workflow process. Here's an example of an order fulfillment process:

Order Fulfillment workflow

workflow-order-fulfillment (6K)

The explanation of this diagram is as follows:

Places are inactive. All the places do is hold tokens representing the state of the process. If, for example, there's a token in place D above, then that means we're ready to pack the order.

Transitions are active. They move tokens from their input places (the places that have an arc pointing into the transition) to their output places (the places you get to by following the arcs going out of the transition). When this happens the transition is said to fire.

Transitions can only fire when there's at least one FREE token in each input place. When that is the case, the transition is enabled. That the transition is enabled means it is able to fire. It will fire when the conditions of its trigger are satisfied.

When the workflow is started, a token is placed in the start place (A in the example). This enables the automatic transition 'Charge Credit Card'.

The transition fires with a success or a failure. If it was successful, it produces a token in place D. If there was a failure, it produces a token in place B. Thus, the outcome of the attempt at charging the credit card governs the further routing of the process. The rule is that firing a transition consumes one token from each of its input places, and places a token on each of its output places for which the guard is true. The guard is a predicate, in this case the [success] and [failure] on the arcs going out of 'Charge Credit Card'. Guards are what enables us to do conditional routing. The 'Charge Credit Card' transition acts as an explicit or-split, because it chooses either one route or the other.

The other form of conditional routing, which is the implicit or-split, is what chooses between the transitions 'Update Billing Information' and 'Cancel Order'. Since there's only one token in place C, only one of the two transitions can have it. But, contrary to the explicit or-split, where the decision is explicitly made as soon as 'Charge Credit Card' finishes, the choice between 'Update Billing Information' and 'Cancel Order' is made as late as possible.

Both transitions will be enabled when there's a token in place C (i.e. when the spam has been sent). If the user updates his billing information before the timed 'Cancel Order' transition times out, 'Cancel Order' is never fired. And vice versa: If the order is canceled (which will probably involve spamming the user again to let him know that his order was cancelled), then he won't be able to update his billing information and will have to enter a new order. Thus, the choice is made implicitly, based on the timing.

The guard will generally depend on case attributes. The 'Charge Credit Card' transition above will set a case attribute to either 'success' or 'failure', and the guard will check this value to determine its result. Case attributes can hold more complex values than simple yes/no values, but the guard must always be either true or false.

What is missing from this diagram is the process which initiates a new workflow instance (or 'case') and puts a token in the start place. In the above example the case initiator would be 'Take Customer Order'. In this implementation the activity which initiates a workflow case is shown as start_task_id on the WORKFLOW table.


Database Design

The main issue for a workflow management system is answering the question 'who must do what, when and how'. Some of these components already exist within my application, which is available for download from http://www.radicore.org, while others will need to be created separately.

What These are the transitions which represent tasks, or something to be done such as: giving authorization, updating a database, sending an e-mail, loading a truck, filling a form, printing a document and so on. These are the identities of application tasks and will have an entry on the TASK table within the MENU database.
When When a transition or task is performed depends on its position within the workflow process and the placing of tokens on all its input places during the execution of each case.
How Each transition or task will point to a particular entry on the TASK table within the MENU database which in turn will provide the location and name of the application script which will carry out the necessary processing.
Who A transition or task which must be triggered by a human participant may be assigned to a single human or a group of humans. Within my MENU database individual people are identified on the USER table and groups of people are identified on the ROLE table.

Workflow E-R Diagram

Here is the Entity-Relationship (E-R) Diagram for my workflow tables:

E-R Diagram

WORKFLOW table PLACE table TRANSITION table ARC table CASE table TOKEN table WORKITEM table workflow-er-diagram (4K)

 

E-R Diagram description
These tables are for defining workflow processes.
WORKFLOW This table holds the definition for each workflow process, such as 'Order Fulfillment'.
PLACE This table holds the details for each place within a workflow process.
TRANSITION This table holds the details for each transition within a workflow process, such as 'Charge Customer', 'Pack Order' and 'Ship Order'. Each record will point to an application task within the MENU database.
ARC This table holds the details for each arc within a workflow process. An arc links a place to a transition.
These tables are for individual workflow instances or cases.
CASE This identifies when a particular instance of a workflow was started, its context and its current status. It is possible for a workflow to have multiple open cases at any one time.
TOKEN This identifies when a token was inserted into a particular place.
WORKITEM A record is created here when a transition is enabled or able to fire. Entries which are to be triggered by a human participant will appear on the Menu/Home Page of relevant users so that they can see what tasks are pending and select any for processing. Each of these entries will be a hyperlink which, when pressed, will cause the relevant application task to be activated with the correct context already loaded.

WORKFLOW table

The structure of this table is as follows:

CREATE TABLE `wf_workflow` (
  `workflow_id` smallint(5) unsigned NOT NULL default '0',
  `workflow_name` varchar(80) NOT NULL default '',
  `workflow_desc` text,
  `start_task_id` varchar(40) NOT NULL default '',
  `is_valid` char(1) NOT NULL default 'N',
  `workflow_errors` text,
  `start_date` date default NULL,
  `end_date` date default NULL,
  `created_date` datetime NOT NULL default '0000-00-00 00:00:00',
  `created_user` varchar(16) default NULL,
  `revised_date` datetime default NULL,
  `revised_user` varchar(16) default NULL,
 PRIMARY KEY  (`workflow_id`)
) ENGINE=MyISAM;
FieldTypeDescription
workflow_id NUMERIC Unique identity assigned by the system.
workflow_name STRING Required. Short name.
workflow_desc STRING Optional. Long description.
start_task_id STRING Required. The identity of the application task which, when executed, creates a new workflow case and puts a token on the start place.
is_valid BOOLEAN Default is NO. After defining all the places, transitions and arcs for a workflow process it must be validated before it can be used. This field shows the result of that validation.
workflow_errors STRING Read only. This contains any error messages from the last validation process. If there are errors then IS_VALID is set to NO.
start_date DATE Required. Identifies the date on which this workflow process, if valid, comes into existence. It cannot be used to create cases before this date.
end_date DATE Optional. Identifies the date on which this workflow process ceases to be valid. It cannot be used to create cases after this date.

The start and end dates can thus be used to phase one definition out and bring another one in on a particular date.

The following fields are set automatically by the system:
created_date DATE+TIME The date and time on which this record was created.
created_user STRING The identity of the user who created this record.
revised_date DATE+TIME The date and time on which this record was last changed.
revised_user STRING The identity of the user who last changed this record.

PLACE table

The structure of this table is as follows:

CREATE TABLE `wf_place` (
  `workflow_id` smallint(5) unsigned NOT NULL default '0',
  `place_id` smallint(5) unsigned NOT NULL default '0',
  `place_type` char(1) NOT NULL default '5',
  `place_name` varchar(80) NOT NULL default '',
  `place_desc` text,
  `created_date` datetime NOT NULL default '0000-00-00 00:00:00',
  `created_user` varchar(16) default NULL,
  `revised_date` datetime default NULL,
  `revised_user` varchar(16) default NULL,
  PRIMARY KEY  (`workflow_id`,`place_id`)
) ENGINE=MyISAM;
FieldTypeDescription
workflow_id NUMERIC Required. Points to an entry on the WORKFLOW table.
place_id NUMERIC Unique identity assigned by the system.
place_type STRING Required. Valid options are:
  • 1 = start place (there can be only one).
  • 5 = intermediate place (there can be any number).
  • 9 = end place (there can be only one).
When a new workflow process is created a start place and an end place will be created automatically. The user is responsible for creating all the intermediate places.
place_name STRING Required. Short name.
place_desc STRING Optional. Long description.

TRANSITION table

The structure of this table is as follows:

CREATE TABLE `wf_transition` (
  `workflow_id` smallint(5) unsigned NOT NULL default '0',
  `transition_id` smallint(5) unsigned NOT NULL default '0',
  `transition_name` varchar(80) NOT NULL default '',
  `transition_desc` text,
  `transition_trigger` varchar(4) NOT NULL default 'USER',
  `time_limit` int(11) unsigned default NULL,
  `task_id` varchar(40) NOT NULL default '',
  `role_id` varchar(16) default NULL,
  `created_date` datetime NOT NULL default '0000-00-00 00:00:00',
  `created_user` varchar(16) default NULL,
  `revised_date` datetime default NULL,
  `revised_user` varchar(16) default NULL,
  PRIMARY KEY  (`workflow_id`,`transition_id`)
) ENGINE=MyISAM;
FieldTypeDescription
workflow_id NUMERIC Required. Points to an entry on the WORKFLOW table.
transition_id NUMERIC Unique identity assigned by the system.
transition_name STRING Required. Short name.
transition_desc STRING Optional. Long description.
transition_trigger STRING Required. Identifies how this transition will be triggered. Valid options are:
  • USER - manually by a user.
  • AUTO - automatically by the system.
  • MSG - by an external event.
  • TIME - after a time limit has expired.

A transition cannot be fired until there is at least one FREE token on each of its input places.

If it is fired successfully then tokens will be created on each of its output places.

time_limit NUMERIC Optional. Only valid if transition_trigger='TIME'. It is a value in minutes, but is displayed and input in hours and minutes. Valid values are between '0:01' and '999:59'.
task_id STRING Required. The identity of the application task which will be activated when this transition is fired.

Note that a task which has been identified as the starting task for a workflow cannot also be used as a transition within any workflow as the act of firing that transition within a workflow case will cause the creation of a new workflow case.

role_id STRING Optional. The identity of the group of users (ROLE) to which this workitem will be assigned when the entry is created. If this is non-blank the corresponding workitem will be available to all users who share that role and not a single specified user.

ARC table

The structure of this table is as follows:

CREATE TABLE `wf_arc` (
  `workflow_id` smallint(5) unsigned NOT NULL default '0',
  `transition_id` smallint(5) unsigned NOT NULL default '0',
  `place_id` smallint(5) unsigned NOT NULL default '0',
  `direction` char(3) NOT NULL default '',
  `arc_type` varchar(10) NOT NULL default 'SEQ',
  `condition_field` varchar(40) NULL,      
  `condition_operator` varchar(4) NULL,
  `condition_value` varchar(40) NULL,
  `created_date` datetime NOT NULL default '0000-00-00 00:00:00',
  `created_user` varchar(16) default NULL,
  `revised_date` datetime default NULL,
  `revised_user` varchar(16) default NULL,
 PRIMARY KEY  (`workflow_id`,`transition_id`,`place_id`,`direction`),
  KEY `place_id` (`workflow_id`,`place_id`,`direction`),
  KEY `transition_id` (`workflow_id`,`transition_id`,`direction`)
) ENGINE=MyISAM;
FieldTypeDescription
workflow_id NUMERIC Required. Points to an entry on the WORKFLOW table.
transition_id NUMERIC Required. Points to an entry on the TRANSITION table.
place_id NUMERIC Required. Points to an entry on the PLACE table.
direction STRING Required. The possible options are:
arc_type STRING Required. Identifies if the arc is a join or split within the current routing. Possible options are:
condition_field STRING Optional. Only valid if 'Arc Type' is set to Explicit OR split.

If this field is supplied then condition_operator and condition_value must also be supplied. They will be used in the sequence "field operator value" to perform a test on the current object's data.

Must be in the format 'name' or 'strlen(name)' where 'name' identifies a field in the current $fieldarray. The value of this field will then become the subject of a comparison. The 'strlen' prefix will cause the length of the value to be used instead of the value itself.

A transition can have two or more output arcs of this type, and a condition must be defined in all except the last one. At runtime these entries will be sorted by place_name and the object's current data, as held in $fieldarray, will be compared using the specified condition. Each comparison will produce a result of either TRUE or FALSE, and if TRUE it will cause the arc containing the condition to be chosen for processing. If the result is not TRUE then the next arc will be evaluated instead. If no conditions evaluate to TRUE then the last arc will be treated as the default.

Input values such as 'name1', '>' and '10' will be treated the same as the following program code:

if ($fieldarray['name1'] > 10) {
    return TRUE;
} else {
    return FALSE;
} // if

Input values such as 'strlen(name1)', '>' and '10' will be treated the same as the following program code:

if (strlen($fieldarray['name1']) > 10) {
    return TRUE;
} else {
    return FALSE;
} // if

Input values such as 'name1', '>' and 'name2', where 'name2' also exists as a name in $fieldarray, will be treated the same as the following program code:

if ($fieldarray['name1'] > $fieldarray['name2']) {
    return TRUE;
} else {
    return FALSE;
} // if
condition_operator STRING Optional. If condition_field is not empty then this must also be not empty. Valid values are:
  • <> (not equal)
  • <= (less than or equal)
  • < (less than)
  • >= (greater than or equal)
  • > (greater than)
  • = (equal)
  • != (not equal)
  • === (equal - same type)
  • !== (not equal - same type)
condition_value STRING Optional. If condition_field is not empty then this must also be not empty.

This can be a number or a string. If it is a string which matches the name of an entry in the current $fieldarray, then the value of that entry will be used instead.

CASE table

The structure of this table is as follows:

CREATE TABLE `wf_case` (
  `case_id` int(10) unsigned NOT NULL default '0',
  `workflow_id` smallint(5) unsigned NOT NULL default '0',
  `context` varchar(255) NOT NULL default '',
  `case_status` char(2) NOT NULL default 'OP',
  `start_date` datetime NOT NULL default '0000-00-00 00:00:00',
  `end_date` datetime default NULL,
  `created_date` datetime NOT NULL default '0000-00-00 00:00:00',
  `created_user` varchar(16) default NULL,
  `revised_date` datetime default NULL,
  `revised_user` varchar(16) default NULL,
  PRIMARY KEY  (`case_id`),
  KEY `workflow_id` (`workflow_id`)
) ENGINE=MyISAM;
FieldTypeDescription
case_id NUMERIC Unique identity assigned by the system.
workflow_id NUMERIC Required. Points to an entry on the WORKFLOW table.
context STRING The primary key of the database entry to which this case refers in the format of an sql WHERE clause, as explained in Appendix I. This is produced by the application task identified in START_TASK_ID on the WORKFLOW table.
case_status STRING Required. Possible options are:
  • OP - Open
  • CL - Closed
  • SU - Suspended
  • CA - Cancelled
start_date DATE+TIME Set by the system when this entry is opened.
end_date DATE+TIME Set by the system when this entry is closed. This occurs when a token is placed in the end place.

TOKEN table

The structure of this table is as follows:

CREATE TABLE `wf_token` (
  `case_id` int(10) unsigned NOT NULL default '0',
  `token_id` smallint(5) unsigned NOT NULL default '0',
  `workflow_id` smallint(6) unsigned NOT NULL default '0',
  `place_id` smallint(5) unsigned NOT NULL default '0',
  `context` varchar(255) NOT NULL default '',
  `token_status` varchar(4) NOT NULL default 'FREE',
  `enabled_date` datetime NOT NULL default '0000-00-00 00:00:00',
  `cancelled_date` datetime default NULL,
  `consumed_date` datetime default NULL,
  PRIMARY KEY  (`case_id`,`token_id`),
  KEY `place_id` (`workflow_id`,`place_id`)
) ENGINE=MyISAM;
FieldTypeDescription
case_id NUMERIC Required. Points to an entry on the CASE table.
token_id NUMERIC Unique identity assigned by the system.
workflow_id NUMERIC Required. Points to an entry on the WORKFLOW table.
place_id NUMERIC Required. Points to an entry on the PLACE table.
context STRING The primary key of the database entry as passed down by the previous transition (application task).
token_status STRING Required. Possible options are:
  • FREE - Free
  • LOCK - Locked
  • CONS - Consumed
  • CANC - Cancelled

When a token is created it will automatically have a FREE status. A token on an input place must be FREE before a transition can be fired.

enabled_date DATE+TIME The date and time on which this token appeared in this place.
cancelled_date DATE+TIME The date and time on which this token was cancelled.
consumed_date DATE+TIME The date and time on which this token was consumed by a transition being fired.

WORKITEM table

The structure of this table is as follows:

CREATE TABLE `wf_workitem` (
  `case_id` int(10) unsigned NOT NULL default '0',
  `workitem_id` smallint(5) unsigned NOT NULL default '0',
  `workflow_id` smallint(6) unsigned NOT NULL default '0',
  `transition_id` smallint(5) unsigned NOT NULL default '0',
  `transition_trigger` varchar(4) NOT NULL default 'USER',
  `task_id` varchar(40) NOT NULL default '',
  `context` varchar(255) NOT NULL default '',
  `workitem_status` char(2) NOT NULL default 'EN',
  `enabled_date` datetime default NULL,
  `cancelled_date` datetime default NULL,
  `finished_date` datetime default NULL,
  `deadline` datetime default NULL,
  `role_id` varchar(16) default NULL,
  `user_id` varchar(16) default NULL,
  PRIMARY KEY  (`case_id`,`workitem_id`),
  KEY `transition_id` (`workflow_id`,`transition_id`)
) ENGINE=MyISAM;
FieldTypeDescription
case_id NUMERIC Required. Points to an entry on the CASE table.
workitem_id NUMERIC Unique identity assigned by the system.
workflow_id NUMERIC Required. Points to an entry on the WORKFLOW table.
transition_id NUMERIC Required. Points to an entry on the TRANSITION table.
transition_trigger STRING Set by the system. Shows how this transition was fired. Valid options are:

A transition cannot be fired until there is at least one FREE token on each of its input places.

If it is fired successfully then tokens will be created on each of its output places.

task_id STRING Identity of an entry on the TASK table in the MENU database that will be activated when this workitem is processed.
context STRING The primary key of a database entry that will be passed to the application task when this workitem is processed.
workitem_status STRING Required. Possible options are:
  • EN - Enabled
  • IP - In Progress
  • CA - Cancelled
  • FI - Finished
enabled_date DATE+TIME The data and time on which this workitem was enabled.
cancelled_date DATE+TIME The data and time on which this workitem was cancelled.
finished_date DATE+TIME The data and time on which this workitem was finished.
deadline DATE+TIME If the transition_trigger='TIME' this is the date and time on which the deadline expires.
role_id STRING Identity of an entry on the ROLE table in the MENU database.
user_id STRING Identity of an entry on the USER table in the MENU database.

Maintenance Screens

These are the maintenance screens for the Workflow system:

Workflow Processes
List Workflow Process
Add Workflow Process
Delete Workflow Process
Enquire Workflow Process
Search Workflow Process
Update Workflow Process
Validate Workflow Process
Workflow Places
List Workflow Place
Add Workflow Place
Delete Workflow Place
Enquire Workflow Place
Search Workflow Place
Update Workflow Place
Workflow Transitions
List Workflow Transition
Add Workflow Transition
Delete Workflow Transition
Enquire Workflow Transition
Search Workflow Transition
Update Workflow Transition
Workflow Arcs
List Workflow Arc
Add Workflow Arc
Delete Workflow Arc
Enquire Workflow Arc
Search Workflow Arc
Update Workflow Arc
Workflow Cases
List Workflow Case
List Case within Workflow
Enquire Workflow Case
Search Workflow Case
Workflow Tokens
List Workflow Token
List Token within Case
Enquire Workflow Token
Search Workflow Token
Workflow Workitems
List Workflow Workitem
List Workitem within Case
Enquire Workflow Workitem
Search Workflow Workitem
List Outstanding Workitems

The Workflow Engine

Having defined a workflow process the next step is to have a means whereby instances (or 'cases') of that process can be created then progressed from one stage to the next. This is where the 'engine' comes in. This is the piece of software that monitors every action to see if it requires the creation of a new workflow case or the updating of an existing one.

One feature of my infrastructure design is that every database access (select, insert, update and delete) goes through my abstract table class. Because of this design feature I therefore have a single class in which it is possible to trap all database activity within the system, and therefore I can implement my workflow engine without having to make modifications to huge numbers of scripts.

There are two significant points to consider with this implementation:

Creating a new workflow Case

Trapping when a new database record has just been created is very simple as new records are created through the insertRecord() method of my generic table class. Similarly all updates go through the updateRecord() method. All I have to do is insert the following code at the end of these methods:

        if (empty($this->errors)) {
            // additions to the workflow database do not count
            if ($this->dbname != 'workflow') {
                // find out if this task/context has any workflow connections
                $this->_examineWorkflow($fieldarray);
            } // if
        } // if
        
        return $fieldarray;
    
    } // insertRecord

The _examineWorkflow() method will perform the following:

Updating an existing workflow Case

This involves looking for an outstanding WORKITEM during the execution of the insertRecord() and updateRecord() methods which matches the current task identity and context. The selection criteria is as follows:

Thus 'Pack Order where customer_id=1234' will involve a different WORKITEM to 'Pack Order where customer_id=5678'.

If a record is found where its primary key matches the current context then the following checks are made:

If the insert or update is successful then the transition/workitem is said to have been fired, which has the following effect:

Note that a transaction which is included in a workflow must perform a database commit() (with or without an actual database update) so that the workflow engine can be informed that the transaction has been completed successfully. If the transaction terminates without performing a commit() then the workflow engine will take no action.

Result of Creating a Token

Whenever a token is created in a place the following checks are made:

Running batch tasks with AUTO triggers

Tasks in the menu system are designed to be run in one of two ways:

Batch tasks are run in the background, do not have any dialog with the user, can be run automatically at scheduled times via cron or a task scheduler, and can stay active for extended periods.

When a transition is processed and a token is moved from an input place to an output place, this may enable a subsequent transition. If this subsequent transition has an AUTO trigger then it will be run immediately. While it is possible for an online transition to be followed by an AUTO-triggered transition which is either online or batch, it is only possible for a batch transition to be followed by an AUTO-triggered transition which is also batch. It is not possible for a batch transition to be followed by an AUTO-triggered transition which is designed to be run online.


Conclusion

As you can see designing and building a workflow system is not a trivial matter. The major steps are:

I do not claim that this design is perfect, but how does it compare to yours?


Frequently Asked Questions (FAQ)

  1. How do I use the Workflow system?
  2. Why doesn't the Workflow system have a facility for sending emails?
  3. Why don't you store state-specific info in the 'context' field of a workflow case?
  4. How can I customise the text of pending workflow items on the menu/home page?
  5. How can I control the sequence in which the conditions on Explicit OR Splits are evaluated?
  6. What happens when a place contains more than one token?
  7. How are workitems assigned to users in the Workflow system?

References


Amendment History

01 Nov 2016 Added References
Updated Frequently Asked Questions (FAQ)
Amended implicit OR split to allow more than two arcs, and removed the restriction that one of them must be triggered by a timer.
30 Jan 2016 Added Running batch tasks with AUTO triggers.
01 May 2015 Amended ARC table to split the pre_condition column into separate parts called condition_field, condition_operator and condition_value.
01 May 2010 Amended TRANSITION table to allow the time_limit to be specified in hours and minutes instead of just hours.
01 Mar 2010 Modified Explicit OR split to allow more than two arcs of this type to come out of a transition.
Updated Frequently Asked Questions (FAQ).
18 Oct 2009 Added Frequently Asked Questions (FAQ).
20 Aug 2007 Added the ability to fire the triggers of workitems with deadlines which have passed via an online screen instead of a background process.

counter