Galaxia workflow api port for egroupware

This commit is contained in:
alpeb 2004-08-07 19:58:49 +00:00
parent 6322ce9832
commit 52a3cae790
41 changed files with 4664 additions and 0 deletions

View File

@ -0,0 +1,3 @@
<?php
//Code shared by all activities (pos)
?>

View File

@ -0,0 +1,3 @@
<?php
//Code shared by all the activities (pre)
?>

View File

@ -0,0 +1,3 @@
<?php
//Code to be executed after an activity
?>

View File

@ -0,0 +1,20 @@
<?php
//Code to be executed before an activity
// If we didn't retrieve the instance before
if(empty($instance->instanceId)) {
// This activity needs an instance to be passed to
// be started, so get the instance into $instance.
if(isset($_REQUEST['iid'])) {
$instance->getInstance($_REQUEST['iid']);
} else {
// defined in lib/Galaxia/config.php
galaxia_show_error("No instance indicated");
die;
}
}
// Set the current user for this activity
if(isset($user) && !empty($instance->instanceId) && !empty($activity->activityId)) {
$instance->setActivityUser($activity->activityId,$user);
}
?>

View File

@ -0,0 +1,3 @@
<?php
//Code to be executed after the end activity
?>

View File

@ -0,0 +1,20 @@
<?php
//Code to be executed before the end activity
// If we didn't retrieve the instance before
if(empty($instance->instanceId)) {
// This activity needs an instance to be passed to
// be started, so get the instance into $instance.
if(isset($_REQUEST['iid'])) {
$instance->getInstance($_REQUEST['iid']);
} else {
// defined in lib/Galaxia/config.php
galaxia_show_error("No instance indicated");
die;
}
}
// Set the current user for this activity
if(isset($user) && !empty($instance->instanceId) && !empty($activity->activityId)) {
$instance->setActivityUser($activity->activityId,$user);
}
?>

View File

@ -0,0 +1,3 @@
<?php
//Code to be executed after a join activity
?>

View File

@ -0,0 +1,20 @@
<?php
//Code to be executed before a join activity
// If we didn't retrieve the instance before
if(empty($instance->instanceId)) {
// This activity needs an instance to be passed to
// be started, so get the instance into $instance.
if(isset($_REQUEST['iid'])) {
$instance->getInstance($_REQUEST['iid']);
} else {
// defined in lib/Galaxia/config.php
galaxia_show_error("No instance indicated");
die;
}
}
// Set the current user for this activity
if(isset($user) && !empty($instance->instanceId) && !empty($activity->activityId)) {
$instance->setActivityUser($activity->activityId,$user);
}
?>

View File

@ -0,0 +1,3 @@
<?php
//Code to be executed after a split activity
?>

View File

@ -0,0 +1,20 @@
<?php
//Code to be executed before a split activity
// If we didn't retrieve the instance before
if(empty($instance->instanceId)) {
// This activity needs an instance to be passed to
// be started, so get the instance into $instance.
if(isset($_REQUEST['iid'])) {
$instance->getInstance($_REQUEST['iid']);
} else {
// defined in lib/Galaxia/config.php
galaxia_show_error("No instance indicated");
die;
}
}
// Set the current user for this activity
if(isset($user) && !empty($instance->instanceId) && !empty($activity->activityId)) {
$instance->setActivityUser($activity->activityId,$user);
}
?>

View File

@ -0,0 +1,3 @@
<?php
//Code to be executed after a standalone activity
?>

View File

@ -0,0 +1,3 @@
<?php
//Code to be executed before a standalone activity
?>

View File

@ -0,0 +1,3 @@
<?php
//Code to be executed after a start activity
?>

View File

@ -0,0 +1,11 @@
<?php
//Code to be executed before a start activity
// If we didn't retrieve the instance before
if(empty($instance->instanceId) && isset($_REQUEST['iid'])) {
// in case we're looping back to a start activity, we need to retrieve the instance
$instance->getInstance($_REQUEST['iid']);
} else {
// otherwise we'll create an instance when this activity is completed
}
?>

View File

@ -0,0 +1,3 @@
<?php
//Code to be executed after a switch activity
?>

View File

@ -0,0 +1,20 @@
<?php
//Code to be executed before a switch activity
// If we didn't retrieve the instance before
if(empty($instance->instanceId)) {
// This activity needs an instance to be passed to
// be started, so get the instance into $instance.
if(isset($_REQUEST['iid'])) {
$instance->getInstance($_REQUEST['iid']);
} else {
// defined in lib/Galaxia/config.php
galaxia_show_error("No instance indicated");
die;
}
}
// Set the current user for this activity
if(isset($user) && !empty($instance->instanceId) && !empty($activity->activityId)) {
$instance->setActivityUser($activity->activityId,$user);
}
?>

View File

@ -0,0 +1,125 @@
<?php
/**
* Configuration of the Galaxia Workflow Engine for E-Groupware
*/
// Common prefix used for all database table names, e.g. galaxia_
if (!defined('GALAXIA_TABLE_PREFIX')) {
define('GALAXIA_TABLE_PREFIX', 'egw_wf_');
}
// Directory containing the Galaxia library, e.g. lib/Galaxia
if (!defined('GALAXIA_LIBRARY')) {
define('GALAXIA_LIBRARY', dirname(__FILE__));
}
// filesystem Operations
$GLOBALS['phpgw']->vfs = createobject('phpgwapi.vfs');
// check if basedir exists
$test=$GLOBALS['phpgw']->vfs->get_real_info(array('string' => '/', 'relatives' => array(RELATIVE_NONE), 'relative' => False));
if($test[mime_type]!='Directory')
{
die(lang('Base directory does not exist, please ask adminstrator to check the global configuration'));
}
// check if /workflow exists
$test = @$GLOBALS['phpgw']->vfs->get_real_info(array('string' => '/workflow', 'relatives' => array(RELATIVE_NONE), 'relative' => False));
if($test[mime_type]!='Directory')
{
// if not, create it
$GLOBALS['phpgw']->vfs->override_acl = 1;
$GLOBALS['phpgw']->vfs->mkdir(array(
'string' => '/workflow',
'relatives' => array(RELATIVE_NONE)
));
$GLOBALS['phpgw']->vfs->override_acl = 0;
// test one more time
$test = $GLOBALS['phpgw']->vfs->get_real_info(array('string' => '/workflow', 'relatives' => array(RELATIVE_NONE), 'relative' => False));
if($test[mime_type]!='Directory')
{
die(lang('/workflow directory does not exist and could not be created, please ask adminstrator to check the global configuration'));
}
}
// Directory where the Galaxia processes will be stored, e.g. lib/Galaxia/processes
if (!defined('GALAXIA_PROCESSES'))
{
// Note: this directory must be writeable by the webserver !
define('GALAXIA_PROCESSES', $GLOBALS['phpgw']->vfs->basedir.SEP.'workflow');
}
// Directory where a *copy* of the Galaxia activity templates will be stored, e.g. templates
// Define as '' if you don't want to copy templates elsewhere
if (!defined('GALAXIA_TEMPLATES')) {
// Note: this directory must be writeable by the webserver !
define('GALAXIA_TEMPLATES', '');
}
// Default header to be added to new activity templates
if (!defined('GALAXIA_TEMPLATE_HEADER')) {
define('GALAXIA_TEMPLATE_HEADER', '');
}
// File where the ProcessManager logs for Galaxia will be saved, e.g. lib/Galaxia/log/pm.log
// Define as '' if you don't want to use logging
if (!defined('GALAXIA_LOGFILE')) {
// Note: this file must be writeable by the webserver !
//define('GALAXIA_LOGFILE', GALAXIA_LIBRARY . '/log/pm.log');
define('GALAXIA_LOGFILE', '');
}
// Directory containing the GraphViz 'dot' and 'neato' programs, in case
// your webserver can't find them via its PATH environment variable
if (!defined('GRAPHVIZ_BIN_DIR')) {
define('GRAPHVIZ_BIN_DIR', '');
//define('GRAPHVIZ_BIN_DIR', 'd:/wintools/ATT/GraphViz/bin');
}
// language function
function tra($msg, $m1='', $m2='', $m3='', $m4='')
{
return lang($msg, $m1, $m2, $m3, $m4);
}
// Specify how error messages should be shown
if (!function_exists('galaxia_show_error')) {
function galaxia_show_error($msg)
{
die("Error: $msg");
}
}
// Specify how to execute a non-interactive activity (for use in src/API/Instance.php)
if (!function_exists('galaxia_execute_activity')) {
function galaxia_execute_activity($activityId = 0, $iid = 0, $auto = 1)
{
// Now execute the code for the activity but we are in a method!
// so just use an fopen with http mode
/* $parsed = parse_url($_SERVER["REQUEST_URI"]);
$URI = 'http'.((isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] == 'on')) ? 's' : '').'://'.$_SERVER['HTTP_HOST'].$parsed["path"];
$parts = explode('/',$URI);
$parts[count($parts)-1] = "index.php?sessionid=".SID."&menuaction=workflow.run_activity&activityId=$activityId&amp;iid=$iid&amp;auto=$auto";
$URI = implode('/',$parts);
$fp = fopen($URI,"r");
$data = '';
if (!$fp) {
trigger_error(tra("Fatal error: cannot execute automatic activity $activityId"),E_USER_WARNING);
die;
}
while (!feof($fp)) {
$data.=fread($fp,8192);
}
fclose($fp);
*/
$run_activity = CreateObject('workflow.run_activity.go');
$data = $run_activity->go($activityId, $iid, $auto);
}
}
?>

View File

@ -0,0 +1,218 @@
<?php
include_once (GALAXIA_LIBRARY.'/src/common/Base.php');
//!! Abstract class representing activities
//! An abstract class representing activities
/*!
This class represents activities, and must be derived for
each activity type supported in the system. Derived activities extending this
class can be found in the activities subfolder.
This class is observable.
*/
class BaseActivity extends Base {
var $name;
var $normalizedName;
var $description;
var $isInteractive;
var $isAutoRouted;
var $roles=Array();
var $outbound=Array();
var $inbound=Array();
var $pId;
var $activityId;
var $type;
function setDb($db)
{
$this->db=$db;
}
function BaseActivity($db)
{
$this->db=$db;
$this->type='base';
}
/*!
Factory method returning an activity of the desired type
loading the information from the database.
*/
function getActivity($activityId)
{
$query = "select * from `".GALAXIA_TABLE_PREFIX."activities` where `activityId`=?";
$result = $this->query($query,array($activityId));
if(!$result->numRows()) return false;
$res = $result->fetchRow();
switch($res['type']) {
case 'start':
$act = new Start($this->db);
break;
case 'end':
$act = new End($this->db);
break;
case 'join':
$act = new Join($this->db);
break;
case 'split':
$act = new Split($this->db);
break;
case 'standalone':
$act = new Standalone($this->db);
break;
case 'switch':
$act = new SwitchActivity($this->db);
break;
case 'activity':
$act = new Activity($this->db);
break;
default:
trigger_error('Unknown activity type:'.$res['type'],E_USER_WARNING);
}
$act->setName($res['name']);
$act->setProcessId($res['pId']);
$act->setNormalizedName($res['normalized_name']);
$act->setDescription($res['description']);
$act->setIsInteractive($res['isInteractive']);
$act->setIsAutoRouted($res['isAutoRouted']);
$act->setActivityId($res['activityId']);
$act->setType($res['type']);
//Now get forward transitions
//Now get backward transitions
//Now get roles
$query = "select `roleId` from `".GALAXIA_TABLE_PREFIX."activity_roles` where `activityId`=?";
$result=$this->query($query,array($res['activityId']));
while($res = $result->fetchRow()) {
$this->roles[] = $res['roleId'];
}
$act->setRoles($this->roles);
return $act;
}
/*! Returns an Array of roleIds for the given user */
function getUserRoles($user) {
$query = "select `roleId` from `".GALAXIA_TABLE_PREFIX."user_roles` where `user`=?";
$result=$this->query($query,array($user));
$ret = Array();
while($res = $result->fetchRow()) {
$ret[] = $res['roleId'];
}
return $ret;
}
/*! Returns an Array of asociative arrays with roleId and name
for the given user */
function getActivityRoleNames() {
$aid = $this->activityId;
$query = "select gr.`roleId`, `name` from `".GALAXIA_TABLE_PREFIX."activity_roles` gar, `".GALAXIA_TABLE_PREFIX."roles` gr where gar.`roleId`=gr.`roleId` and gar.`activityId`=?";
$result=$this->query($query,array($aid));
$ret = Array();
while($res = $result->fetchRow()) {
$ret[] = $res;
}
return $ret;
}
/*! Returns the normalized name for the activity */
function getNormalizedName() {
return $this->normalizedName;
}
/*! Sets normalized name for the activity */
function setNormalizedName($name) {
$this->normalizedName=$name;
}
/*! Sets the name for the activity */
function setName($name) {
$this->name=$name;
}
/*! Gets the activity name */
function getName() {
return $this->name;
}
/*! Sets the activity description */
function setDescription($desc) {
$this->description=$desc;
}
/*! Gets the activity description */
function getDescription() {
return $this->description;
}
/*! Sets the type for the activity - this does NOT allow you to change the actual type */
function setType($type) {
$this->type=$type;
}
/*! Gets the activity type */
function getType() {
return $this->type;
}
/*! Sets if the activity is interactive */
function setIsInteractive($is) {
$this->isInteractive=$is;
}
/*! Returns if the activity is interactive */
function isInteractive() {
return $this->isInteractive == 'y';
}
/*! Sets if the activity is auto-routed */
function setIsAutoRouted($is) {
$this->isAutoRouted = $is;
}
/*! Gets if the activity is auto routed */
function isAutoRouted() {
return $this->isAutoRouted == 'y';
}
/*! Sets the processId for this activity */
function setProcessId($pid) {
$this->pId=$pid;
}
/*! Gets the processId for this activity*/
function getProcessId() {
return $this->pId;
}
/*! Gets the activityId */
function getActivityId() {
return $this->activityId;
}
/*! Sets the activityId */
function setActivityId($id) {
$this->activityId=$id;
}
/*! Gets array with roleIds asociated to this activity */
function getRoles() {
return $this->roles;
}
/*! Sets roles for this activities, shoule receive an
array of roleIds */
function setRoles($roles) {
$this->roles = $roles;
}
/*! Checks if a user has a certain role (by name) for this activity,
e.g. $isadmin = $activity->checkUserRole($user,'admin'); */
function checkUserRole($user,$rolename) {
$aid = $this->activityId;
return $this->getOne("select count(*) from `".GALAXIA_TABLE_PREFIX."activity_roles` gar, `".GALAXIA_TABLE_PREFIX."user_roles` gur, `".GALAXIA_TABLE_PREFIX."roles` gr where gar.`roleId`=gr.`roleId` and gur.`roleId`=gr.`roleId` and gar.`activityId`=? and gur.`user`=? and gr.`name`=?",array($aid, $user, $rolename));
}
}
?>

View File

@ -0,0 +1,655 @@
<?php
include_once (GALAXIA_LIBRARY.'/src/common/Base.php');
//!! Instance
//! A class representing a process instance.
/*!
This class represents a process instance, it is used when any activity is
executed. The $instance object is created representing the instance of a
process being executed in the activity or even a to-be-created instance
if the activity is a start activity.
*/
class Instance extends Base {
var $properties = Array();
var $owner = '';
var $status = '';
var $started;
var $nextActivity;
var $nextUser;
var $ended;
/// Array of asocs(activityId,status,started,user)
var $activities = Array();
var $pId;
var $instanceId = 0;
/// An array of workitem ids
var $workitems = Array();
function Instance($db) {
$this->db = $db;
}
/*!
Method used to load an instance data from the database.
*/
function getInstance($instanceId) {
// Get the instance data
$query = "select * from `".GALAXIA_TABLE_PREFIX."instances` where `instanceId`=?";
$result = $this->query($query,array((int)$instanceId));
if(!$result->numRows()) return false;
$res = $result->fetchRow();
//Populate
$this->properties = unserialize($res['properties']);
$this->status = $res['status'];
$this->pId = $res['pId'];
$this->instanceId = $res['instanceId'];
$this->owner = $res['owner'];
$this->started = $res['started'];
$this->ended = $res['ended'];
$this->nextActivity = $res['nextActivity'];
$this->nextUser = $res['nextUser'];
// Get the activities where the instance is (ids only is ok)
$query = "select * from `".GALAXIA_TABLE_PREFIX."instance_activities` where `instanceId`=?";
$result = $this->query($query,array((int)$instanceId));
while($res = $result->fetchRow()) {
$this->activities[]=$res;
}
}
/*!
Sets the next activity to be executed, if the current activity is
a switch activity the complete() method will use the activity setted
in this method as the next activity for the instance.
Note that this method receives an activity name as argument. (Not an Id)
*/
function setNextActivity($actname) {
$pId = $this->pId;
$actname=trim($actname);
$aid = $this->getOne("select `activityId` from `".GALAXIA_TABLE_PREFIX."activities` where `pId`=? and `name`=?",array($pId,$actname));
if(!$this->getOne("select count(*) from `".GALAXIA_TABLE_PREFIX."activities` where `activityId`=? and `pId`=?",array($aid,$pId))) {
trigger_error(tra('Fatal error: setting next activity to an unexisting activity'),E_USER_WARNING);
}
$this->nextActivity=$aid;
$query = "update `".GALAXIA_TABLE_PREFIX."instances` set `nextActivity`=? where `instanceId`=?";
$this->query($query,array((int)$aid,(int)$this->instanceId));
}
/*!
This method can be used to set the user that must perform the next
activity of the process. this effectively "assigns" the instance to
some user.
*/
function setNextUser($user) {
$pId = $this->pId;
$this->nextUser = $user;
$query = "update `".GALAXIA_TABLE_PREFIX."instances` set `nextUser`=? where `instanceId`=?";
$this->query($query,array($user,(int)$this->instanceId));
}
/*!
\private
Creates a new instance.
This method is called in start activities when the activity is completed
to create a new instance representing the started process.
*/
function _createNewInstance($activityId,$user) {
// Creates a new instance setting up started,ended,user
// and status
$pid = $this->getOne("select `pId` from `".GALAXIA_TABLE_PREFIX."activities` where `activityId`=?",array((int)$activityId));
$this->status = 'active';
$this->nextActivity = 0;
$this->setNextUser('');
$this->pId = $pid;
$now = date("U");
$this->started=$now;
$this->owner = $user;
$props=serialize($this->properties);
$query = "insert into `".GALAXIA_TABLE_PREFIX."instances`(`started`,`ended`,`status`,`pId`,`owner`,`properties`) values(?,?,?,?,?,?)";
$this->query($query,array($now,0,'active',$pid,$user,$props));
$this->instanceId = $this->getOne("select max(`instanceId`) from `".GALAXIA_TABLE_PREFIX."instances` where `started`=? and `owner`=?",array((int)$now,$user));
$iid=$this->instanceId;
// Now update the properties!
$props = serialize($this->properties);
$query = "update `".GALAXIA_TABLE_PREFIX."instances` set `properties`=? where `instanceId`=?";
$this->query($query,array($props,(int)$iid));
// Then add in ".GALAXIA_TABLE_PREFIX."instance_activities an entry for the
// activity the user and status running and started now
$query = "insert into `".GALAXIA_TABLE_PREFIX."instance_activities`(`instanceId`,`activityId`,`user`,`started`,`status`) values(?,?,?,?,?)";
$this->query($query,array((int)$iid,(int)$activityId,$user,(int)$now,'running'));
}
/*!
Sets a property in this instance. This method is used in activities to
set instance properties. Instance properties are inemdiately serialized.
*/
function set($name,$value) {
$this->properties[$name] = $value;
$props = serialize($this->properties);
$query = "update `".GALAXIA_TABLE_PREFIX."instances` set `properties`=? where `instanceId`=?";
$this->query($query,array($props,$this->instanceId));
}
/*!
Gets the value of an instance property.
*/
function get($name) {
if(isset($this->properties[$name])) {
return $this->properties[$name];
} else {
return false;
}
}
/*!
Returns an array of asocs describing the activities where the instance
is present, can be more than one activity if the instance was "splitted"
*/
function getActivities() {
return $this->activities;
}
/*!
Gets the instance status can be
'completed', 'active', 'aborted' or 'exception'
*/
function getStatus() {
return $this->status;
}
/*!
Sets the instance status , the value can be:
'completed', 'active', 'aborted' or 'exception'
*/
function setStatus($status) {
$this->status = $status;
// and update the database
$query = "update `".GALAXIA_TABLE_PREFIX."instances` set `status`=? where `instanceId`=?";
$this->query($query,array($status,(int)$this->instanceId));
}
/*!
Returns the instanceId
*/
function getInstanceId() {
return $this->instanceId;
}
/*!
Returns the processId for this instance
*/
function getProcessId() {
return $this->pId;
}
/*!
Returns the user that created the instance
*/
function getOwner() {
return $this->owner;
}
/*!
Sets the instance creator user
*/
function setOwner($user) {
$this->owner = $user;
// save database
$query = "update `".GALAXIA_TABLE_PREFIX."instances` set `owner`=? where `instanceId`=?";
$this->query($query,array($owner,(int)$this->instanceId));
}
/*!
Sets the user that must execute the activity indicated by the activityId.
Note that the instance MUST be present in the activity to set the user,
you can't program who will execute an activity.
*/
function setActivityUser($activityId,$theuser) {
if(empty($theuser)) $theuser='*';
for($i=0;$i<count($this->activities);$i++) {
if($this->activities[$i]['activityId']==$activityId) {
$this->activities[$i]['user']=$theuser;
$query = "update `".GALAXIA_TABLE_PREFIX."instance_activities` set `user`=? where `activityId`=? and `instanceId`=?";
$this->query($query,array($theuser,(int)$activityId,(int)$this->instanceId));
}
}
}
/*!
Returns the user that must execute or is already executing an activity
wherethis instance is present.
*/
function getActivityUser($activityId) {
for($i=0;$i<count($this->activities);$i++) {
if($this->activities[$i]['activityId']==$activityId) {
return $this->activities[$i]['user'];
}
}
return false;
}
/*!
Sets the status of the instance in some activity, can be
'running' or 'completed'
*/
function setActivityStatus($activityId,$status) {
for($i=0;$i<count($this->activities);$i++) {
if($this->activities[$i]['activityId']==$activityId) {
$this->activities[$i]['status']=$status;
$query = "update `".GALAXIA_TABLE_PREFIX."instance_activities` set `status`=? where `activityId`=? and `instanceId`=?";
$this->query($query,array($status,(int)$activityId,(int)$this->instanceId));
}
}
}
/*!
Gets the status of the instance in some activity, can be
'running' or 'completed'
*/
function getActivityStatus($activityId) {
for($i=0;$i<count($this->activities);$i++) {
if($this->activities[$i]['activityId']==$activityId) {
return $this->activities[$i]['status'];
}
}
return false;
}
/*!
Resets the start time of the activity indicated to the current time.
*/
function setActivityStarted($activityId) {
$now = date("U");
for($i=0;$i<count($this->activities);$i++) {
if($this->activities[$i]['activityId']==$activityId) {
$this->activities[$i]['started']=$now;
$query = "update `".GALAXIA_TABLE_PREFIX."instance_activities` set `started`=? where `activityId`=? and `instanceId`=?";
$this->query($query,array($now,(int)$activityId,(int)$this->instanceId));
}
}
}
/*!
Gets the Unix timstamp of the starting time for the given activity.
*/
function getActivityStarted($activityId) {
for($i=0;$i<count($this->activities);$i++) {
if($this->activities[$i]['activityId']==$activityId) {
return $this->activities[$i]['started'];
}
}
return false;
}
/*!
\private
Gets an activity from the list of activities of the instance
*/
function _get_instance_activity($activityId) {
for($i=0;$i<count($this->activities);$i++) {
if($this->activities[$i]['activityId']==$activityId) {
return $this->activities[$i];
}
}
return false;
}
/*!
Sets the time where the instance was started.
*/
function setStarted($time) {
$this->started=$time;
$query = "update `".GALAXIA_TABLE_PREFIX."instances` set `started`=? where `instanceId`=?";
$this->query($query,array((int)$time,(int)$this->instanceId));
}
/*!
Gets the time where the instance was started (Unix timestamp)
*/
function getStarted() {
return $this->started;
}
/*!
Sets the end time of the instance (when the process was completed)
*/
function setEnded($time) {
$this->ended=$time;
$query = "update `".GALAXIA_TABLE_PREFIX."instances` set `ended`=? where `instanceId`=?";
$this->query($query,array((int)$time,(int)$this->instanceId));
}
/*!
Gets the end time of the instance (when the process was completed)
*/
function getEnded() {
return $this->ended;
}
/*!
Completes an activity, normally from any activity you should call this
function without arguments.
The arguments are explained just in case.
$activityId is the activity that is being completed, when this is not
passed the engine takes it from the $_REQUEST array,all activities
are executed passing the activityId in the URI.
$force indicates that the instance must be routed no matter if the
activity is auto-routing or not. This is used when "sending" an
instance from a non-auto-routed activity to the next activity.
$addworkitem indicates if a workitem should be added for the completed
activity.
YOU MUST NOT CALL complete() for non-interactive activities since
the engine does automatically complete automatic activities after
executing them.
*/
function complete($activityId=0,$force=false,$addworkitem=true) {
global $user;
global $__activity_completed;
$__activity_completed = true;
if(empty($user)) {$theuser='*';} else {$theuser=$user;}
if($activityId==0) {
$activityId=$_REQUEST['activityId'];
}
// If we are completing a start activity then the instance must
// be created first!
$type = $this->getOne("select `type` from `".GALAXIA_TABLE_PREFIX."activities` where `activityId`=?",array((int)$activityId));
if($type=='start') {
$this->_createNewInstance((int)$activityId,$theuser);
}
// Now set ended
$now = date("U");
$query = "update `".GALAXIA_TABLE_PREFIX."instance_activities` set `ended`=? where `activityId`=? and `instanceId`=?";
$this->query($query,array((int)$now,(int)$activityId,(int)$this->instanceId));
//Add a workitem to the instance
$iid = $this->instanceId;
if($addworkitem) {
$max = $this->getOne("select max(`orderId`) from `".GALAXIA_TABLE_PREFIX."workitems` where `instanceId`=?",array((int)$iid));
if(!$max) {
$max=1;
} else {
$max++;
}
$act = $this->_get_instance_activity($activityId);
if(!$act) {
//Then this is a start activity ending
$started = $this->getStarted();
$putuser = $this->getOwner();
} else {
$started=$act['started'];
$putuser = $act['user'];
}
$ended = date("U");
$properties = serialize($this->properties);
$query="insert into `".GALAXIA_TABLE_PREFIX."workitems`(`instanceId`,`orderId`,`activityId`,`started`,`ended`,`properties`,`user`) values(?,?,?,?,?,?,?)";
$this->query($query,array((int)$iid,(int)$max,(int)$activityId,(int)$started,(int)$ended,$properties,$putuser));
}
//Set the status for the instance-activity to completed
$this->setActivityStatus($activityId,'completed');
//If this and end actt then terminate the instance
if($type=='end') {
$this->terminate();
return;
}
//If the activity ending is autorouted then send to the
//activity
if ($type != 'end') {
if (($force) || ($this->getOne("select `isAutoRouted` from `".GALAXIA_TABLE_PREFIX."activities` where `activityId`=?",array($activityId)) == 'y')) {
// Now determine where to send the instance
$query = "select `actToId` from `".GALAXIA_TABLE_PREFIX."transitions` where `actFromId`=?";
$result = $this->query($query,array((int)$activityId));
$candidates = Array();
while ($res = $result->fetchRow()) {
$candidates[] = $res['actToId'];
}
if($type == 'split') {
$first = true;
foreach ($candidates as $cand) {
$this->sendTo($activityId,$cand,$first);
$first = false;
}
} elseif($type == 'switch') {
if (in_array($this->nextActivity,$candidates)) {
$this->sendTo((int)$activityId,(int)$this->nextActivity);
} else {
trigger_error(tra('Fatal error: nextActivity does not match any candidate in autorouting switch activity'),E_USER_WARNING);
}
} else {
if (count($candidates)>1) {
trigger_error(tra('Fatal error: non-deterministic decision for autorouting activity'),E_USER_WARNING);
} else {
$this->sendTo((int)$activityId,(int)$candidates[0]);
}
}
}
}
}
/*!
Aborts an activity and terminates the whole instance. We still create a workitem to keep track
of where in the process the instance was aborted
*/
function abort($activityId=0,$theuser = '',$addworkitem=true) {
if(empty($theuser)) {
global $user;
if (empty($user)) {$theuser='*';} else {$theuser=$user;}
}
if($activityId==0) {
$activityId=$_REQUEST['activityId'];
}
// If we are completing a start activity then the instance must
// be created first!
$type = $this->getOne("select `type` from `".GALAXIA_TABLE_PREFIX."activities` where `activityId`=?",array((int)$activityId));
if($type=='start') {
$this->_createNewInstance((int)$activityId,$theuser);
}
// Now set ended
$now = date("U");
$query = "update `".GALAXIA_TABLE_PREFIX."instance_activities` set `ended`=? where `activityId`=? and `instanceId`=?";
$this->query($query,array((int)$now,(int)$activityId,(int)$this->instanceId));
//Add a workitem to the instance
$iid = $this->instanceId;
if($addworkitem) {
$max = $this->getOne("select max(`orderId`) from `".GALAXIA_TABLE_PREFIX."workitems` where `instanceId`=?",array((int)$iid));
if(!$max) {
$max=1;
} else {
$max++;
}
$act = $this->_get_instance_activity($activityId);
if(!$act) {
//Then this is a start activity ending
$started = $this->getStarted();
$putuser = $this->getOwner();
} else {
$started=$act['started'];
$putuser = $act['user'];
}
$ended = date("U");
$properties = serialize($this->properties);
$query="insert into `".GALAXIA_TABLE_PREFIX."workitems`(`instanceId`,`orderId`,`activityId`,`started`,`ended`,`properties`,`user`) values(?,?,?,?,?,?,?)";
$this->query($query,array((int)$iid,(int)$max,(int)$activityId,(int)$started,(int)$ended,$properties,$putuser));
}
//Set the status for the instance-activity to aborted
// TODO: support 'aborted' if we keep activities after termination some day
//$this->setActivityStatus($activityId,'aborted');
// terminate the instance with status 'aborted'
$this->terminate('aborted');
}
/*!
Terminates the instance marking the instance and the process
as completed. This is the end of a process.
Normally you should not call this method since it is automatically
called when an end activity is completed.
*/
function terminate($status = 'completed') {
//Set the status of the instance to completed
$now = date("U");
$query = "update `".GALAXIA_TABLE_PREFIX."instances` set `status`=?, `ended`=? where `instanceId`=?";
$this->query($query,array($status,(int)$now,(int)$this->instanceId));
$query = "delete from `".GALAXIA_TABLE_PREFIX."instance_activities` where `instanceId`=?";
$this->query($query,array((int)$this->instanceId));
$this->status = $status;
$this->activities = Array();
}
/*!
Sends the instance from some activity to another activity.
You should not call this method unless you know very very well what
you are doing.
*/
function sendTo($from,$activityId,$split=false) {
//1: if we are in a join check
//if this instance is also in
//other activity if so do
//nothing
$type = $this->getOne("select `type` from `".GALAXIA_TABLE_PREFIX."activities` where `activityId`=?",array((int)$activityId));
// Verify the existance of a transition
if(!$this->getOne("select count(*) from `".GALAXIA_TABLE_PREFIX."transitions` where `actFromId`=? and `actToId`=?",array($from,(int)$activityId))) {
trigger_error(tra('Fatal error: trying to send an instance to an activity but no transition found'),E_USER_WARNING);
}
//try to determine the user or *
//Use the nextUser
if($this->nextUser) {
$putuser = $this->nextUser;
} else {
$candidates = Array();
$query = "select `roleId` from `".GALAXIA_TABLE_PREFIX."activity_roles` where `activityId`=?";
$result = $this->query($query,array((int)$activityId));
while ($res = $result->fetchRow()) {
$roleId = $res['roleId'];
$query2 = "select `user` from `".GALAXIA_TABLE_PREFIX."user_roles` where `roleId`=?";
$result2 = $this->query($query2,array((int)$roleId));
while ($res2 = $result2->fetchRow()) {
$candidates[] = $res2['user'];
}
}
if(count($candidates) == 1) {
$putuser = $candidates[0];
} else {
$putuser = '*';
}
}
//update the instance_activities table
//if not splitting delete first
//please update started,status,user
if(!$split) {
$query = "delete from `".GALAXIA_TABLE_PREFIX."instance_activities` where `instanceId`=? and `activityId`=?";
$this->query($query,array((int)$this->instanceId,$from));
}
$now = date("U");
$iid = $this->instanceId;
$query="delete from `".GALAXIA_TABLE_PREFIX."instance_activities` where `instanceId`=? and `activityId`=?";
$this->query($query,array((int)$iid,(int)$activityId));
$query="insert into `".GALAXIA_TABLE_PREFIX."instance_activities`(`instanceId`,`activityId`,`user`,`status`,`started`) values(?,?,?,?,?)";
$this->query($query,array((int)$iid,(int)$activityId,$putuser,'running',(int)$now));
//we are now in a new activity
$this->activities=Array();
$query = "select * from `".GALAXIA_TABLE_PREFIX."instance_activities` where `instanceId`=?";
$result = $this->query($query,array((int)$iid));
while ($res = $result->fetchRow()) {
$this->activities[]=$res;
}
if ($type == 'join') {
if (count($this->activities)>1) {
// This instance will have to wait!
return;
}
}
//if the activity is not interactive then
//execute the code for the activity and
//complete the activity
$isInteractive = $this->getOne("select `isInteractive` from `".GALAXIA_TABLE_PREFIX."activities` where `activityId`=?",array((int)$activityId));
if ($isInteractive=='n') {
// Now execute the code for the activity (function defined in lib/Galaxia/config.php)
galaxia_execute_activity($activityId, $iid , 1);
// Reload in case the activity did some change
$this->getInstance($this->instanceId);
$this->complete($activityId);
}
}
/*!
Gets a comment for this instance
*/
function get_instance_comment($cId) {
$iid = $this->instanceId;
$query = "select * from `".GALAXIA_TABLE_PREFIX."instance_comments` where `instanceId`=? and `cId`=?";
$result = $this->query($query,array((int)$iid,(int)$cId));
$res = $result->fetchRow();
return $res;
}
/*!
Inserts or updates an instance comment
*/
function replace_instance_comment($cId, $activityId, $activity, $user, $title, $comment) {
if (!$user) {
$user = 'Anonymous';
}
$iid = $this->instanceId;
if ($cId) {
$query = "update `".GALAXIA_TABLE_PREFIX."instance_comments` set `title`=?,`comment`=? where `instanceId`=? and `cId`=?";
$this->query($query,array($title,$comment,(int)$iid,(int)$cId));
} else {
$hash = md5($title.$comment);
if ($this->getOne("select count(*) from `".GALAXIA_TABLE_PREFIX."instance_comments` where `instanceId`=? and `hash`=?",array($iid,$hash))) {
return false;
}
$now = date("U");
$query ="insert into `".GALAXIA_TABLE_PREFIX."instance_comments`(`instanceId`,`user`,`activityId`,`activity`,`title`,`comment`,`timestamp`,`hash`) values(?,?,?,?,?,?,?,?)";
$this->query($query,array((int)$iid,$user,(int)$activityId,$activity,$title,$comment,(int)$now,$hash));
}
}
/*!
Removes an instance comment
*/
function remove_instance_comment($cId) {
$iid = $this->instanceId;
$query = "delete from `".GALAXIA_TABLE_PREFIX."instance_comments` where `cId`=? and `instanceId`=?";
$this->query($query,array((int)$cId,(int)$iid));
}
/*!
Lists instance comments
*/
function get_instance_comments() {
$iid = $this->instanceId;
$query = "select * from `".GALAXIA_TABLE_PREFIX."instance_comments` where `instanceId`=? order by ".$this->convert_sortmode("timestamp_desc");
$result = $this->query($query,array((int)$iid));
$ret = Array();
while($res = $result->fetchRow()) {
$ret[] = $res;
}
return $ret;
}
}
?>

View File

@ -0,0 +1,76 @@
<?php
include_once (GALAXIA_LIBRARY.'/src/common/Base.php');
//!! Process.php
//! A class representing a process
/*!
This class representes the process that is being executed when an activity
is executed. You can access this class methods using $process from any activity.
No need to instantiate a new object.
*/
class Process extends Base {
var $name;
var $description;
var $version;
var $normalizedName;
var $pId = 0;
function Process($db) {
$this->db=$db;
}
/*!
Loads a process form the database
*/
function getProcess($pId) {
$query = "select * from `".GALAXIA_TABLE_PREFIX."processes` where `pId`=?";
$result = $this->query($query,array($pId));
if(!$result->numRows()) return false;
$res = $result->fetchRow();
$this->name = $res['name'];
$this->description = $res['description'];
$this->normalizedName = $res['normalized_name'];
$this->version = $res['version'];
$this->pId = $res['pId'];
}
/*!
Gets the normalized name of the process
*/
function getNormalizedName() {
return $this->normalizedName;
}
/*!
Gets the process name
*/
function getName() {
return $this->name;
}
/*!
Gets the process version
*/
function getVersion() {
return $this->version;
}
/*!
Gets information about an activity in this process by name,
e.g. $actinfo = $process->getActivityByName('Approve CD Request');
if ($actinfo) {
$some_url = 'tiki-g-run_activity.php?activityId=' . $actinfo['activityId'];
}
*/
function getActivityByName($actname) {
// Get the activity data
$query = "select * from `".GALAXIA_TABLE_PREFIX."activities` where `pId`=? and `name`=?";
$pId = $this->pId;
$result = $this->query($query,array($pId,$actname));
if(!$result->numRows()) return false;
$res = $result->fetchRow();
return $res;
}
}
?>

View File

@ -0,0 +1,12 @@
<?php
include_once (GALAXIA_LIBRARY.'/src/common/Base.php');
//!! Role.php
//! A class representing a role.
/*!
Not yet implemented.
*/
//\todo Implement this class
class Role extends Base {
}
?>

View File

@ -0,0 +1,16 @@
<?php
include_once (GALAXIA_LIBRARY.'/src/common/Base.php');
//!! Workitem.php
//! A class representing workitems
/*!
Not yet implemented
*/
class Workitem extends Base {
var $instance;
var $properties=Array();
var $started;
var $ended;
var $activity;
}
?>

View File

@ -0,0 +1,14 @@
<?php
include_once(GALAXIA_LIBRARY.'/src/API/BaseActivity.php');
//!! Activity
//!
/*!
This class handles activities of type 'activity'
*/
class Activity extends BaseActivity {
function Activity($db)
{
$this->setDb($db);
}
}
?>

View File

@ -0,0 +1,14 @@
<?php
include_once(GALAXIA_LIBRARY.'/src/API/BaseActivity.php');
//!! End
//! End class
/*!
This class handles activities of type 'end'
*/
class End extends BaseActivity {
function End($db)
{
$this->setDb($db);
}
}
?>

View File

@ -0,0 +1,14 @@
<?php
include_once(GALAXIA_LIBRARY.'/src/API/BaseActivity.php');
//!! Join
//! Join class
/*!
This class handles activities of type 'join'
*/
class Join extends BaseActivity {
function Join($db)
{
$this->setDb($db);
}
}
?>

View File

@ -0,0 +1,14 @@
<?php
include_once(GALAXIA_LIBRARY.'/src/API/BaseActivity.php');
//!! Split
//! Split class
/*!
This class handles activities of type 'split'
*/
class Split extends BaseActivity {
function Split($db)
{
$this->setDb($db);
}
}
?>

View File

@ -0,0 +1,14 @@
<?php
include_once(GALAXIA_LIBRARY.'/src/API/BaseActivity.php');
//!! Standalone
//! Standalone class
/*!
This class handles activities of type 'standalone'
*/
class Standalone extends BaseActivity {
function Standalone($db)
{
$this->setDb($db);
}
}
?>

View File

@ -0,0 +1,14 @@
<?php
include_once(GALAXIA_LIBRARY.'/src/API/BaseActivity.php');
//!! Start
//! Start class
/*!
This class handles activities of type 'start'
*/
class Start extends BaseActivity {
function Start($db)
{
$this->setDb($db);
}
}
?>

View File

@ -0,0 +1,14 @@
<?php
include_once(GALAXIA_LIBRARY.'/src/API/BaseActivity.php');
//!! SwitchActivity
//! SwitchActivity class
/*!
This class handles activities of type 'switch'
*/
class SwitchActivity extends BaseActivity {
function SwitchActivity($db)
{
$this->setDb($db);
}
}
?>

View File

@ -0,0 +1,315 @@
<?php
include_once(GALAXIA_LIBRARY.'/src/common/Base.php');
//!! GUI
//! A GUI class for use in typical user interface scripts
/*!
This class provides methods for use in typical user interface scripts
*/
class GUI extends Base {
/*!
List user processes, user processes should follow one of these conditions:
1) The process has an instance assigned to the user
2) The process has a begin activity with a role compatible to the
user roles
3) The process has an instance assigned to '*' and the
roles for the activity match the roles assigned to
the user
The method returns the list of processes that match this
and it also returns the number of instances that are in the
process matching the conditions.
*/
function gui_list_user_processes($user,$offset,$maxRecords,$sort_mode,$find,$where='')
{
// FIXME: this doesn't support multiple sort criteria
//$sort_mode = $this->convert_sortmode($sort_mode);
$sort_mode = str_replace("_"," ",$sort_mode);
$mid = "where gp.isActive=? and gur.user=?";
$bindvars = array('y',$user);
if($find) {
$findesc = '%'.$find.'%';
$mid .= " and ((gp.name like ?) or (gp.description like ?))";
$bindvars[] = $findesc;
$bindvars[] = $findesc;
}
if($where) {
$mid.= " and ($where) ";
}
$query = "select distinct(gp.pId),
gp.isActive,
gp.name as procname,
gp.normalized_name as normalized_name,
gp.version as version
from ".GALAXIA_TABLE_PREFIX."processes gp
INNER JOIN ".GALAXIA_TABLE_PREFIX."activities ga ON gp.pId=ga.pId
INNER JOIN ".GALAXIA_TABLE_PREFIX."activity_roles gar ON gar.activityId=ga.activityId
INNER JOIN ".GALAXIA_TABLE_PREFIX."roles gr ON gr.roleId=gar.roleId
INNER JOIN ".GALAXIA_TABLE_PREFIX."user_roles gur ON gur.roleId=gr.roleId
$mid order by $sort_mode";
$query_cant = "select count(distinct(gp.pId))
from ".GALAXIA_TABLE_PREFIX."processes gp
INNER JOIN ".GALAXIA_TABLE_PREFIX."activities ga ON gp.pId=ga.pId
INNER JOIN ".GALAXIA_TABLE_PREFIX."activity_roles gar ON gar.activityId=ga.activityId
INNER JOIN ".GALAXIA_TABLE_PREFIX."roles gr ON gr.roleId=gar.roleId
INNER JOIN ".GALAXIA_TABLE_PREFIX."user_roles gur ON gur.roleId=gr.roleId
$mid";
$result = $this->query($query,$bindvars,$maxRecords,$offset);
$cant = $this->getOne($query_cant,$bindvars);
$ret = Array();
while($res = $result->fetchRow()) {
// Get instances per activity
$pId=$res['pId'];
$res['activities']=$this->getOne("select count(distinct(ga.activityId))
from ".GALAXIA_TABLE_PREFIX."processes gp
INNER JOIN ".GALAXIA_TABLE_PREFIX."activities ga ON gp.pId=ga.pId
INNER JOIN ".GALAXIA_TABLE_PREFIX."activity_roles gar ON gar.activityId=ga.activityId
INNER JOIN ".GALAXIA_TABLE_PREFIX."roles gr ON gr.roleId=gar.roleId
INNER JOIN ".GALAXIA_TABLE_PREFIX."user_roles gur ON gur.roleId=gr.roleId
where gp.pId=? and gur.user=?",
array($pId,$user));
$res['instances']=$this->getOne("select count(distinct(gi.instanceId))
from ".GALAXIA_TABLE_PREFIX."instances gi
INNER JOIN ".GALAXIA_TABLE_PREFIX."instance_activities gia ON gi.instanceId=gia.instanceId
INNER JOIN ".GALAXIA_TABLE_PREFIX."activity_roles gar ON gia.activityId=gar.activityId
INNER JOIN ".GALAXIA_TABLE_PREFIX."user_roles gur ON gar.roleId=gur.roleId
where gi.pId=? and ((gia.user=?) or (gia.user=? and gur.user=?))",
array($pId,$user,'*',$user));
$ret[] = $res;
}
$retval = Array();
$retval["data"] = $ret;
$retval["cant"] = $cant;
return $retval;
}
function gui_list_user_activities($user,$offset,$maxRecords,$sort_mode,$find,$where='')
{
// FIXME: this doesn't support multiple sort criteria
//$sort_mode = $this->convert_sortmode($sort_mode);
$sort_mode = str_replace("_"," ",$sort_mode);
$mid = "where gp.isActive=? and gur.user=?";
$bindvars = array('y',$user);
if($find) {
$findesc = '%'.$find.'%';
$mid .= " and ((ga.name like ?) or (ga.description like ?))";
$bindvars[] = $findesc;
$bindvars[] = $findesc;
}
if($where) {
$mid.= " and ($where) ";
}
$query = "select distinct(ga.activityId),
ga.name,
ga.type,
gp.name as procname,
ga.isInteractive,
ga.isAutoRouted,
ga.activityId,
gp.version as version,
gp.pId,
gp.isActive
from ".GALAXIA_TABLE_PREFIX."processes gp
INNER JOIN ".GALAXIA_TABLE_PREFIX."activities ga ON gp.pId=ga.pId
INNER JOIN ".GALAXIA_TABLE_PREFIX."activity_roles gar ON gar.activityId=ga.activityId
INNER JOIN ".GALAXIA_TABLE_PREFIX."roles gr ON gr.roleId=gar.roleId
INNER JOIN ".GALAXIA_TABLE_PREFIX."user_roles gur ON gur.roleId=gr.roleId
$mid order by $sort_mode";
$query_cant = "select count(distinct(ga.activityId))
from ".GALAXIA_TABLE_PREFIX."processes gp
INNER JOIN ".GALAXIA_TABLE_PREFIX."activities ga ON gp.pId=ga.pId
INNER JOIN ".GALAXIA_TABLE_PREFIX."activity_roles gar ON gar.activityId=ga.activityId
INNER JOIN ".GALAXIA_TABLE_PREFIX."roles gr ON gr.roleId=gar.roleId
INNER JOIN ".GALAXIA_TABLE_PREFIX."user_roles gur ON gur.roleId=gr.roleId
$mid";
$result = $this->query($query,$bindvars,$maxRecords,$offset);
$cant = $this->getOne($query_cant,$bindvars);
$ret = Array();
while($res = $result->fetchRow()) {
// Get instances per activity
$res['instances']=$this->getOne("select count(distinct(gi.instanceId))
from ".GALAXIA_TABLE_PREFIX."instances gi
INNER JOIN ".GALAXIA_TABLE_PREFIX."instance_activities gia ON gi.instanceId=gia.instanceId
INNER JOIN ".GALAXIA_TABLE_PREFIX."activity_roles gar ON gia.activityId=gar.activityId
INNER JOIN ".GALAXIA_TABLE_PREFIX."user_roles gur ON gar.roleId=gur.roleId
where gia.activityId=? and ((gia.user=?) or (gia.user=? and gur.user=?))",
array($res['activityId'],$user,'*',$user));
$ret[] = $res;
}
$retval = Array();
$retval["data"] = $ret;
$retval["cant"] = $cant;
return $retval;
}
function gui_list_user_instances($user,$offset,$maxRecords,$sort_mode,$find,$where='')
{
// FIXME: this doesn't support multiple sort criteria
//$sort_mode = $this->convert_sortmode($sort_mode);
$sort_mode = str_replace("_"," ",$sort_mode);
$mid = "where (gia.user=? or (gia.user=? and gur.user=?))";
$bindvars = array($user,'*',$user);
if($find) {
$findesc = '%'.$find.'%';
$mid .= " and ((ga.name like ?) or (ga.description like ?))";
$bindvars[] = $findesc;
$bindvars[] = $findesc;
}
if($where) {
$mid.= " and ($where) ";
}
$query = "select distinct(gi.instanceId),
gi.started,
gi.owner,
gia.user,
gi.status,
gia.status as actstatus,
ga.name,
ga.type,
gp.name as procname,
ga.isInteractive,
ga.isAutoRouted,
ga.activityId,
gp.version as version,
gp.pId
from ".GALAXIA_TABLE_PREFIX."instances gi
INNER JOIN ".GALAXIA_TABLE_PREFIX."instance_activities gia ON gi.instanceId=gia.instanceId
INNER JOIN ".GALAXIA_TABLE_PREFIX."activities ga ON gia.activityId = ga.activityId
INNER JOIN ".GALAXIA_TABLE_PREFIX."activity_roles gar ON gia.activityId=gar.activityId
INNER JOIN ".GALAXIA_TABLE_PREFIX."user_roles gur ON gur.roleId=gar.roleId
INNER JOIN ".GALAXIA_TABLE_PREFIX."processes gp ON gp.pId=ga.pId
$mid order by $sort_mode";
$query_cant = "select count(distinct(gi.instanceId))
from ".GALAXIA_TABLE_PREFIX."instances gi
INNER JOIN ".GALAXIA_TABLE_PREFIX."instance_activities gia ON gi.instanceId=gia.instanceId
INNER JOIN ".GALAXIA_TABLE_PREFIX."activities ga ON gia.activityId = ga.activityId
INNER JOIN ".GALAXIA_TABLE_PREFIX."activity_roles gar ON gia.activityId=gar.activityId
INNER JOIN ".GALAXIA_TABLE_PREFIX."user_roles gur ON gur.roleId=gar.roleId
INNER JOIN ".GALAXIA_TABLE_PREFIX."processes gp ON gp.pId=ga.pId
$mid";
$result = $this->query($query,$bindvars,$maxRecords,$offset);
$cant = $this->getOne($query_cant,$bindvars);
$ret = Array();
while($res = $result->fetchRow()) {
// Get instances per activity
$ret[] = $res;
}
$retval = Array();
$retval["data"] = $ret;
$retval["cant"] = $cant;
return $retval;
}
/*!
Abort an instance - this terminates the instance with status 'aborted', and removes all running activities
*/
function gui_abort_instance($user,$activityId,$instanceId)
{
// Users can only abort instances they're currently running, or instances that they're the owner of
if(!$this->getOne("select count(*)
from ".GALAXIA_TABLE_PREFIX."instance_activities gia, ".GALAXIA_TABLE_PREFIX."instances gi
where gia.instanceId=gi.instanceId and activityId=? and gia.instanceId=? and (user=? or owner=?)",
array($activityId,$instanceId,$user,$user)))
return false;
include_once(GALAXIA_LIBRARY.'/src/API/Instance.php');
$instance = new Instance($this->db);
$instance->getInstance($instanceId);
if (!empty($instance->instanceId)) {
$instance->abort($activityId,$user);
}
unset($instance);
}
/*!
Exception handling for an instance - this sets the instance status to 'exception', but keeps all running activities.
The instance can be resumed afterwards via gui_resume_instance().
*/
function gui_exception_instance($user,$activityId,$instanceId)
{
// Users can only do exception handling for instances they're currently running, or instances that they're the owner of
if(!$this->getOne("select count(*)
from ".GALAXIA_TABLE_PREFIX."instance_activities gia, ".GALAXIA_TABLE_PREFIX."instances gi
where gia.instanceId=gi.instanceId and activityId=? and gia.instanceId=? and (user=? or owner=?)",
array($activityId,$instanceId,$user,$user)))
return false;
$query = "update ".GALAXIA_TABLE_PREFIX."instances
set status=?
where instanceId=?";
$this->query($query, array('exception',$instanceId));
}
/*!
Resume an instance - this sets the instance status from 'exception' back to 'active'
*/
function gui_resume_instance($user,$activityId,$instanceId)
{
// Users can only resume instances they're currently running, or instances that they're the owner of
if(!$this->getOne("select count(*)
from ".GALAXIA_TABLE_PREFIX."instance_activities gia, ".GALAXIA_TABLE_PREFIX."instances gi
where gia.instanceId=gi.instanceId and activityId=? and gia.instanceId=? and (user=? or owner=?)",
array($activityId,$instanceId,$user,$user)))
return false;
$query = "update ".GALAXIA_TABLE_PREFIX."instances
set status=?
where instanceId=?";
$this->query($query, array('active',$instanceId));
}
function gui_send_instance($user,$activityId,$instanceId)
{
if(!
($this->getOne("select count(*)
from ".GALAXIA_TABLE_PREFIX."instance_activities
where activityId=? and instanceId=? and user=?",
array($activityId,$instanceId,$user)))
||
($this->getOne("select count(*)
from ".GALAXIA_TABLE_PREFIX."instance_activities gia
INNER JOIN ".GALAXIA_TABLE_PREFIX."activity_roles gar ON gar.activityId=gia.activityId
INNER JOIN ".GALAXIA_TABLE_PREFIX."user_roles gur ON gar.roleId=gur.roleId
where gia.instanceId=? and gia.activityId=? and gia.user=? and gur.user=?",
array($instanceId,$activityId,'*',$user)))
) return false;
include_once(GALAXIA_LIBRARY.'/src/API/Instance.php');
$instance = new Instance($this->db);
$instance->getInstance($instanceId);
$instance->complete($activityId,true,false);
unset($instance);
}
function gui_release_instance($user,$activityId,$instanceId)
{
if(!$this->getOne("select count(*)
from ".GALAXIA_TABLE_PREFIX."instance_activities
where activityId=? and instanceId=? and user=?",
array($activityId,$instanceId,$user))) return false;
$query = "update ".GALAXIA_TABLE_PREFIX."instance_activities
set user=?
where instanceId=? and activityId=?";
$this->query($query, array('*',$instanceId,$activityId));
}
function gui_grab_instance($user,$activityId,$instanceId)
{
// Grab only if roles are ok
if(!$this->getOne("select count(*)
from ".GALAXIA_TABLE_PREFIX."instance_activities gia
INNER JOIN ".GALAXIA_TABLE_PREFIX."activity_roles gar ON gar.activityId=gia.activityId
INNER JOIN ".GALAXIA_TABLE_PREFIX."user_roles gur ON gar.roleId=gur.roleId
where gia.instanceId=? and gia.activityId=? and gia.user=? and gur.user=?",
array($instanceId,$activityId,'*',$user))) return false;
$query = "update ".GALAXIA_TABLE_PREFIX."instance_activities
set user=?
where instanceId=? and activityId=?";
$this->query($query, array($user,$instanceId,$activityId));
}
}
?>

View File

@ -0,0 +1,33 @@
<?php
include_once(GALAXIA_LIBRARY.'/src/common/Observer.php');
//!! Logger
//! Log
/*!
blah....
*/
class Logger extends Observer {
var $_filename;
function Logger($filename) {
$this->_filename = $filename;
$fp = fopen($this->_filename,"a");
if(!$fp) {
trigger_error("Logger cannot append to log file: ".$this->filename,E_USER_WARNING);
}
if($fp) {
fclose($fp);
}
}
function notify($event,$msg) {
// Add a line to the log file.
$fp = fopen($this->_filename,"a");
$date = date("[d/m/Y h:i:s]");
$msg=trim($msg);
fputs($fp,$date." ".$msg."\n");
fclose($fp);
}
}
?>

View File

@ -0,0 +1,842 @@
<?php
include_once(GALAXIA_LIBRARY.'/src/ProcessManager/BaseManager.php');
//!! ActivityManager
//! A class to maniplate process activities and transitions
/*!
This class is used to add,remove,modify and list
activities used in the Workflow engine.
Activities are managed in a per-process level, each
activity belongs to some process.
*/
class ActivityManager extends BaseManager {
var $error='';
/*!
Constructor takes a PEAR::Db object to be used
to manipulate activities in the database.
*/
function ActivityManager($db) {
if(!$db) {
die("Invalid db object passed to activityManager constructor");
}
$this->db = $db;
}
function get_error() {
return $this->error;
}
/*!
Asociates an activity with a role
*/
function add_activity_role($activityId, $roleId) {
$query = "delete from `".GALAXIA_TABLE_PREFIX."activity_roles` where `activityId`=? and `roleId`=?";
$this->query($query,array($activityId, $roleId));
$query = "insert into `".GALAXIA_TABLE_PREFIX."activity_roles`(`activityId`,`roleId`) values(?,?)";
$this->query($query,array($activityId, $roleId));
}
/*!
Gets the roles asociated to an activity
*/
function get_activity_roles($activityId) {
$query = "select activityId,roles.roleId,roles.name
from ".GALAXIA_TABLE_PREFIX."activity_roles gar, ".GALAXIA_TABLE_PREFIX."roles roles
where roles.roleId = gar.roleId and activityId=?";
$result = $this->query($query,array($activityId));
$ret = Array();
while($res = $result->fetchRow()) {
$ret[] = $res;
}
return $ret;
}
/*!
Removes a role from an activity
*/
function remove_activity_role($activityId, $roleId)
{
$query = "delete from ".GALAXIA_TABLE_PREFIX."activity_roles
where activityId=$activityId and roleId=$roleId";
$this->query($query);
}
/*!
Checks if a transition exists
*/
function transition_exists($pid,$actFromId,$actToId)
{
return($this->getOne("select count(*) from ".GALAXIA_TABLE_PREFIX."transitions where pId=$pid and actFromId=$actFromId and actToId=$actToId"));
}
/*!
Adds a transition
*/
function add_transition($pId, $actFromId, $actToId)
{
// No circular transitions allowed
if($actFromId == $actToId) return false;
// Rule: if act is not spl-x or spl-a it can't have more than
// 1 outbound transition.
$a1 = $this->get_activity($pId, $actFromId);
$a2 = $this->get_activity($pId, $actToId);
if(!$a1 || !$a2) return false;
if($a1['type'] != 'switch' && $a1['type'] != 'split') {
if($this->getOne("select count(*) from ".GALAXIA_TABLE_PREFIX."transitions where actFromId=$actFromId")) {
$this->error = tra('Cannot add transition only split activities can have more than one outbound transition');
return false;
}
}
// Rule: if act is standalone no transitions allowed
if($a1['type'] == 'standalone' || $a2['type']=='standalone') return false;
// No inbound to start
if($a2['type'] == 'start') return false;
// No outbound from end
if($a1['type'] == 'end') return false;
$query = "delete from `".GALAXIA_TABLE_PREFIX."transitions` where `actFromId`=? and `actToId`=?";
$this->query($query,array($actFromId, $actToId));
$query = "insert into `".GALAXIA_TABLE_PREFIX."transitions`(`pId`,`actFromId`,`actToId`) values(?,?,?)";
$this->query($query,array($pId, $actFromId, $actToId));
return true;
}
/*!
Removes a transition
*/
function remove_transition($actFromId, $actToId)
{
$query = "delete from ".GALAXIA_TABLE_PREFIX."transitions where actFromId=$actFromId and actToId=$actToId";
$this->query($query);
return true;
}
/*!
Removes all the activity transitions
*/
function remove_activity_transitions($pId, $aid)
{
$query = "delete from ".GALAXIA_TABLE_PREFIX."transitions where pId=$pId and (actFromId=$aid or actToId=$aid)";
$this->query($query);
}
/*!
Returns all the transitions for a process
*/
function get_process_transitions($pId,$actid=0)
{
if(!$actid) {
$query = "select a1.name as actFromName, a2.name as actToName, actFromId, actToId from ".GALAXIA_TABLE_PREFIX."transitions gt,".GALAXIA_TABLE_PREFIX."activities a1, ".GALAXIA_TABLE_PREFIX."activities a2 where gt.actFromId = a1.activityId and gt.actToId = a2.activityId and gt.pId = $pId";
} else {
$query = "select a1.name as actFromName, a2.name as actToName, actFromId, actToId from ".GALAXIA_TABLE_PREFIX."transitions gt,".GALAXIA_TABLE_PREFIX."activities a1, ".GALAXIA_TABLE_PREFIX."activities a2 where gt.actFromId = a1.activityId and gt.actToId = a2.activityId and gt.pId = $pId and (actFromId = $actid)";
}
$result = $this->query($query);
$ret = Array();
while($res = $result->fetchRow()) {
$ret[] = $res;
}
return $ret;
}
/*!
Indicates if an activity is autoRouted
*/
function activity_is_auto_routed($actid)
{
return($this->getOne("select count(*) from ".GALAXIA_TABLE_PREFIX."activities where activityId=$actid and isAutoRouted='y'"));
}
/*!
Returns all the activities for a process as
an array
*/
function get_process_activities($pId)
{
$query = "select * from ".GALAXIA_TABLE_PREFIX."activities where pId=$pId";
$result = $this->query($query);
$ret = Array();
while($res = $result->fetchRow()) {
$ret[] = $res;
}
return $ret;
}
/*!
Builds the graph
*/
//\todo build the real graph
function build_process_graph($pId)
{
$attributes = Array(
);
$graph = new Process_GraphViz(true,$attributes);
$pm = new ProcessManager($this->db);
$name = $pm->_get_normalized_name($pId);
$graph->set_pid($name);
// Nodes are process activities so get
// the activities and add nodes as needed
$nodes = $this->get_process_activities($pId);
foreach($nodes as $node)
{
if($node['isInteractive']=='y') {
$color='blue';
} else {
$color='black';
}
$auto[$node['name']] = $node['isAutoRouted'];
$graph->addNode($node['name'],array('URL'=>"foourl?activityId=".$node['activityId'],
'label'=>$node['name'],
'shape' => $this->_get_activity_shape($node['type']),
'color' => $color
)
);
}
// Now add edges, edges are transitions,
// get the transitions and add the edges
$edges = $this->get_process_transitions($pId);
foreach($edges as $edge)
{
if($auto[$edge['actFromName']] == 'y') {
$color = 'red';
} else {
$color = 'black';
}
$graph->addEdge(array($edge['actFromName'] => $edge['actToName']), array('color'=>$color));
}
// Save the map image and the image graph
$graph->image_and_map();
unset($graph);
return true;
}
/*!
Validates if a process can be activated checking the
process activities and transitions the rules are:
0) No circular activities
1) Must have only one a start and end activity
2) End must be reachable from start
3) Interactive activities must have a role assigned
4) Roles should be mapped
5) Standalone activities cannot have transitions
6) Non intractive activities non-auto routed must have some role
so the user can "send" the activity
*/
function validate_process_activities($pId)
{
$errors = Array();
// Pre rule no cricular activities
$cant = $this->getOne("select count(*) from ".GALAXIA_TABLE_PREFIX."transitions where pId=$pId and actFromId=actToId");
if($cant) {
$errors[] = tra('Circular reference found some activity has a transition leading to itself');
}
// Rule 1 must have exactly one start and end activity
$cant = $this->getOne("select count(*) from ".GALAXIA_TABLE_PREFIX."activities where pId=$pId and type='start'");
if($cant < 1) {
$errors[] = tra('Process does not have a start activity');
}
$cant = $this->getOne("select count(*) from ".GALAXIA_TABLE_PREFIX."activities where pId=$pId and type='end'");
if($cant != 1) {
$errors[] = tra('Process does not have exactly one end activity');
}
// Rule 2 end must be reachable from start
$nodes = Array();
$endId = $this->getOne("select activityId from ".GALAXIA_TABLE_PREFIX."activities where pId=$pId and type='end'");
$aux['id']=$endId;
$aux['visited']=false;
$nodes[] = $aux;
$startId = $this->getOne("select activityId from ".GALAXIA_TABLE_PREFIX."activities where pId=$pId and type='start'");
$start_node['id']=$startId;
$start_node['visited']=true;
while($this->_list_has_unvisited_nodes($nodes) && !$this->_node_in_list($start_node,$nodes)) {
for($i=0;$i<count($nodes);$i++) {
$node=&$nodes[$i];
if(!$node['visited']) {
$node['visited']=true;
$query = "select actFromId from ".GALAXIA_TABLE_PREFIX."transitions where actToId=".$node['id'];
$result = $this->query($query);
$ret = Array();
while($res = $result->fetchRow()) {
$aux['id'] = $res['actFromId'];
$aux['visited']=false;
if(!$this->_node_in_list($aux,$nodes)) {
$nodes[] = $aux;
}
}
}
}
}
if(!$this->_node_in_list($start_node,$nodes)) {
// Start node is NOT reachable from the end node
$errors[] = tra('End activity is not reachable from start activity');
}
//Rule 3: interactive activities must have a role
//assigned.
//Rule 5: standalone activities can't have transitions
$query = "select * from ".GALAXIA_TABLE_PREFIX."activities where pId = $pId";
$result = $this->query($query);
while($res = $result->fetchRow()) {
$aid = $res['activityId'];
if($res['isInteractive'] == 'y') {
$cant = $this->getOne("select count(*) from ".GALAXIA_TABLE_PREFIX."activity_roles where activityId=".$res['activityId']);
if(!$cant) {
$errors[] = tra('Activity').': '.$res['name'].tra(' is interactive but has no role assigned');
}
} else {
if( $res['type'] != 'end' && $res['isAutoRouted'] == 'n') {
$cant = $this->getOne("select count(*) from ".GALAXIA_TABLE_PREFIX."activity_roles where activityId=".$res['activityId']);
if(!$cant) {
$errors[] = tra('Activity').': '.$res['name'].tra(' is non-interactive and non-autorouted but has no role assigned');
}
}
}
if($res['type']=='standalone') {
if($this->getOne("select count(*) from ".GALAXIA_TABLE_PREFIX."transitions where actFromId=$aid or actToId=$aid")) {
$errors[] = tra('Activity').': '.$res['name'].tra(' is standalone but has transitions');
}
}
}
//Rule4: roles should be mapped
$query = "select * from ".GALAXIA_TABLE_PREFIX."roles where pId = $pId";
$result = $this->query($query);
while($res = $result->fetchRow()) {
$cant = $this->getOne("select count(*) from ".GALAXIA_TABLE_PREFIX."user_roles where roleId=".$res['roleId']);
if(!$cant) {
$errors[] = tra('Role').': '.$res['name'].tra(' is not mapped');
}
}
// End of rules
// Validate process sources
$serrors=$this->validate_process_sources($pId);
$errors = array_merge($errors,$serrors);
$this->error = $errors;
$isValid = (count($errors)==0) ? 'y' : 'n';
$query = "update ".GALAXIA_TABLE_PREFIX."processes set isValid='$isValid' where pId=$pId";
$this->query($query);
$this->_label_nodes($pId);
return ($isValid=='y');
}
/*!
Validate process sources
Rules:
1) Interactive activities (non-standalone) must use complete()
2) Standalone activities must not use $instance
3) Switch activities must use setNextActivity
4) Non-interactive activities cannot use complete()
*/
function validate_process_sources($pid)
{
$errors=Array();
$procname= $this->getOne("select normalized_name from ".GALAXIA_TABLE_PREFIX."processes where pId=$pid");
$query = "select * from ".GALAXIA_TABLE_PREFIX."activities where pId=$pid";
$result = $this->query($query);
while($res = $result->fetchRow()) {
$actname = $res['normalized_name'];
$source = GALAXIA_PROCESSES."/$procname/code/activities/$actname".'.php';
if (!file_exists($source)) {
continue;
}
$fp = fopen($source,'r');
$data='';
while(!feof($fp)) {
$data.=fread($fp,8192);
}
fclose($fp);
if($res['type']=='standalone') {
if(strstr($data,'$instance')) {
$errors[] = tra('Activity '.$res['name'].' is standalone and is using the $instance object');
}
} else {
if($res['isInteractive']=='y') {
if(!strstr($data,'$instance->complete()')) {
$errors[] = tra('Activity '.$res['name'].' is interactive so it must use the $instance->complete() method');
}
} else {
if(strstr($data,'$instance->complete()')) {
$errors[] = tra('Activity '.$res['name'].' is non-interactive so it must not use the $instance->complete() method');
}
}
if($res['type']=='switch') {
if(!strstr($data,'$instance->setNextActivity(')) {
$errors[] = tra('Activity '.$res['name'].' is switch so it must use $instance->setNextActivity($actname) method');
}
}
}
}
return $errors;
}
/*!
Indicates if an activity with the same name exists
*/
function activity_name_exists($pId,$name)
{
$name = addslashes($this->_normalize_name($name));
return $this->getOne("select count(*) from ".GALAXIA_TABLE_PREFIX."activities where pId=$pId and normalized_name='$name'");
}
/*!
Gets a activity fields are returned as an asociative array
*/
function get_activity($pId, $activityId)
{
$query = "select * from ".GALAXIA_TABLE_PREFIX."activities where pId=$pId and activityId=$activityId";
$result = $this->query($query);
$res = $result->fetchRow();
return $res;
}
/*!
Lists activities at a per-process level
*/
function list_activities($pId,$offset,$maxRecords,$sort_mode,$find,$where='')
{
$sort_mode = str_replace("_"," ",$sort_mode);
if($find) {
$findesc = '%'.$find.'%';
$mid=" where pId=? and ((name like ?) or (description like ?))";
$bindvars = array($pId,$findesc,$findesc);
} else {
$mid=" where pId=? ";
$bindvars = array($pId);
}
if($where) {
$mid.= " and ($where) ";
}
$query = "select * from ".GALAXIA_TABLE_PREFIX."activities $mid order by $sort_mode";
$query_cant = "select count(*) from ".GALAXIA_TABLE_PREFIX."activities $mid";
$result = $this->query($query,$bindvars,$maxRecords,$offset);
$cant = $this->getOne($query_cant,$bindvars);
$ret = Array();
while($res = $result->fetchRow()) {
$res['roles'] = $this->getOne("select count(*) from ".GALAXIA_TABLE_PREFIX."activity_roles where activityId=?",array($res['activityId']));
$ret[] = $res;
}
$retval = Array();
$retval["data"] = $ret;
$retval["cant"] = $cant;
return $retval;
}
/*!
Removes a activity.
*/
function remove_activity($pId, $activityId)
{
$pm = new ProcessManager($this->db);
$proc_info = $pm->get_process($pId);
$actname = $this->_get_normalized_name($activityId);
$query = "delete from ".GALAXIA_TABLE_PREFIX."activities where pId=$pId and activityId=$activityId";
$this->query($query);
$query = "select actFromId,actToId from ".GALAXIA_TABLE_PREFIX."transitions where actFromId=$activityId or actToId=$activityId";
$result = $this->query($query);
while($res = $result->fetchRow()) {
$this->remove_transition($res['actFromId'], $res['actToId']);
}
$query = "delete from ".GALAXIA_TABLE_PREFIX."activity_roles where activityId=$activityId";
$this->query($query);
// And we have to remove the user and compiled files
// for this activity
$procname = $proc_info['normalized_name'];
unlink(GALAXIA_PROCESSES."/$procname/code/activities/$actname".'.php');
if (file_exists(GALAXIA_PROCESSES."/$procname/code/templates/$actname".'.tpl')) {
@unlink(GALAXIA_PROCESSES."/$procname/code/templates/$actname".'.tpl');
}
unlink(GALAXIA_PROCESSES."/$procname/compiled/$actname".'.php');
return true;
}
/*!
Updates or inserts a new activity in the database, $vars is an asociative
array containing the fields to update or to insert as needed.
$pId is the processId
$activityId is the activityId
*/
function replace_activity($pId, $activityId, $vars)
{
$TABLE_NAME = GALAXIA_TABLE_PREFIX."activities";
$now = date("U");
$vars['lastModif']=$now;
$vars['pId']=$pId;
$vars['normalized_name'] = $this->_normalize_name($vars['name']);
$pm = new ProcessManager($this->db);
$proc_info = $pm->get_process($pId);
foreach($vars as $key=>$value)
{
$vars[$key]=addslashes($value);
}
if($activityId) {
$oldname = $this->_get_normalized_name($activityId);
// update mode
$first = true;
$query ="update $TABLE_NAME set";
foreach($vars as $key=>$value) {
if(!$first) $query.= ',';
if(!is_numeric($value)) $value="'".$value."'";
$query.= " $key=$value ";
$first = false;
}
$query .= " where pId=$pId and activityId=$activityId ";
$this->query($query);
$newname = $vars['normalized_name'];
// if the activity is changing name then we
// should rename the user_file for the activity
// remove the old compiled file and recompile
// the activity
$user_file_old = GALAXIA_PROCESSES.'/'.$proc_info['normalized_name'].'/code/activities/'.$oldname.'.php';
$user_file_new = GALAXIA_PROCESSES.'/'.$proc_info['normalized_name'].'/code/activities/'.$newname.'.php';
rename($user_file_old, $user_file_new);
$user_file_old = GALAXIA_PROCESSES.'/'.$proc_info['normalized_name'].'/code/templates/'.$oldname.'.tpl';
$user_file_new = GALAXIA_PROCESSES.'/'.$proc_info['normalized_name'].'/code/templates/'.$newname.'.tpl';
if ($user_file_old != $user_file_new) {
@rename($user_file_old, $user_file_new);
}
$compiled_file = GALAXIA_PROCESSES.'/'.$proc_info['normalized_name'].'/compiled/'.$oldname.'.php';
unlink($compiled_file);
$this->compile_activity($pId,$activityId);
} else {
// When inserting activity names can't be duplicated
if($this->activity_name_exists($pId, $vars['name'])) {
return false;
}
unset($vars['activityId']);
// insert mode
$first = true;
$query = "insert into $TABLE_NAME(";
foreach(array_keys($vars) as $key) {
if(!$first) $query.= ',';
$query.= "$key";
$first = false;
}
$query .=") values(";
$first = true;
foreach(array_values($vars) as $value) {
if(!$first) $query.= ',';
if(!is_numeric($value)) $value="'".$value."'";
$query.= "$value";
$first = false;
}
$query .=")";
$this->query($query);
$activityId = $this->getOne("select max(activityId) from $TABLE_NAME where pId=$pId and lastModif=$now");
$ret = $activityId;
if(!$activityId) {
print("select max(activityId) from $TABLE_NAME where pId=$pId and lastModif=$now");
die;
}
// Should create the code file
$procname = $proc_info["normalized_name"];
$fw = fopen(GALAXIA_PROCESSES."/$procname/code/activities/".$vars['normalized_name'].'.php','w');
fwrite($fw,'<'.'?'.'php'."\n".'?'.'>');
fclose($fw);
if($vars['isInteractive']=='y') {
$fw = fopen(GALAXIA_PROCESSES."/$procname/code/templates/".$vars['normalized_name'].'.tpl','w');
if (defined('GALAXIA_TEMPLATE_HEADER') && GALAXIA_TEMPLATE_HEADER) {
fwrite($fw,GALAXIA_TEMPLATE_HEADER . "\n");
}
fclose($fw);
}
$this->compile_activity($pId,$activityId);
}
// Get the id
return $activityId;
}
/*!
Sets if an activity is interactive or not
*/
function set_interactivity($pId, $actid, $value)
{
$query = "update ".GALAXIA_TABLE_PREFIX."activities set isInteractive='$value' where pId=$pId and activityId=$actid";
$this->query($query);
// If template does not exist then create template
$this->compile_activity($pId,$actid);
}
/*!
Sets if an activity is auto routed or not
*/
function set_autorouting($pId, $actid, $value)
{
$query = "update ".GALAXIA_TABLE_PREFIX."activities set isAutoRouted='$value' where pId=$pId and activityId=$actid";
$this->query($query);
}
/*!
Compiles activity
*/
function compile_activity($pId, $activityId)
{
$act_info = $this->get_activity($pId,$activityId);
$actname = $act_info['normalized_name'];
$pm = new ProcessManager($this->db);
$proc_info = $pm->get_process($pId);
$compiled_file = GALAXIA_PROCESSES.'/'.$proc_info['normalized_name'].'/compiled/'.$act_info['normalized_name'].'.php';
$template_file = GALAXIA_PROCESSES.'/'.$proc_info['normalized_name'].'/code/templates/'.$actname.'.tpl';
$user_file = GALAXIA_PROCESSES.'/'.$proc_info['normalized_name'].'/code/activities/'.$actname.'.php';
$pre_file = GALAXIA_LIBRARY.'/compiler/'.$act_info['type'].'_pre.php';
$pos_file = GALAXIA_LIBRARY.'/compiler/'.$act_info['type'].'_pos.php';
$fw = fopen($compiled_file,"wb");
// First of all add an include to to the shared code
$shared_file = GALAXIA_PROCESSES.'/'.$proc_info['normalized_name'].'/code/shared.php';
fwrite($fw, '<'."?php include_once('$shared_file'); ?".'>'."\n");
// Before pre shared
$fp = fopen(GALAXIA_LIBRARY.'/compiler/_shared_pre.php',"rb");
while (!feof($fp)) {
$data = fread($fp, 4096);
fwrite($fw,$data);
}
fclose($fp);
// Now get pre and pos files for the activity
$fp = fopen($pre_file,"rb");
while (!feof($fp)) {
$data = fread($fp, 4096);
fwrite($fw,$data);
}
fclose($fp);
// Get the user data for the activity
$fp = fopen($user_file,"rb");
while (!feof($fp)) {
$data = fread($fp, 4096);
fwrite($fw,$data);
}
fclose($fp);
// Get pos and write
$fp = fopen($pos_file,"rb");
while (!feof($fp)) {
$data = fread($fp, 4096);
fwrite($fw,$data);
}
fclose($fp);
// Shared pos
$fp = fopen(GALAXIA_LIBRARY.'/compiler/_shared_pos.php',"rb");
while (!feof($fp)) {
$data = fread($fp, 4096);
fwrite($fw,$data);
}
fclose($fp);
fclose($fw);
//Copy the templates
if($act_info['isInteractive']=='y' && !file_exists($template_file)) {
$fw = fopen($template_file,'w');
if (defined('GALAXIA_TEMPLATE_HEADER') && GALAXIA_TEMPLATE_HEADER) {
fwrite($fw,GALAXIA_TEMPLATE_HEADER . "\n");
}
fclose($fw);
}
if($act_info['isInteractive']!='y' && file_exists($template_file)) {
@unlink($template_file);
if (GALAXIA_TEMPLATES && file_exists(GALAXIA_TEMPLATES.'/'.$proc_info['normalized_name']."/$actname.tpl")) {
@unlink(GALAXIA_TEMPLATES.'/'.$proc_info['normalized_name']."/$actname.tpl");
}
}
if (GALAXIA_TEMPLATES && file_exists($template_file)) {
@copy($template_file,GALAXIA_TEMPLATES.'/'.$proc_info['normalized_name']."/$actname.tpl");
}
}
/*!
\private
Returns activity id by pid,name (activity names are unique)
*/
function _get_activity_id_by_name($pid,$name)
{
$name = addslashes($name);
if($this->getOne("select count(*) from ".GALAXIA_TABLE_PREFIX."activities where pId=$pid and name='$name'")) {
return($this->getOne("select activityId from ".GALAXIA_TABLE_PREFIX."activities where pId=$pid and name='$name'"));
} else {
return '';
}
}
/*!
\private Returns the activity shape
*/
function _get_activity_shape($type)
{
switch($type) {
case "start":
return "circle";
case "end":
return "doublecircle";
case "activity":
return "box";
case "split":
return "triangle";
case "switch":
return "diamond";
case "join":
return "invtriangle";
case "standalone":
return "hexagon";
default:
return "egg";
}
}
/*!
\private Returns true if a list contains unvisited nodes
list members are asoc arrays containing id and visited
*/
function _list_has_unvisited_nodes($list)
{
foreach($list as $node) {
if(!$node['visited']) return true;
}
return false;
}
/*!
\private Returns true if a node is in a list
list members are asoc arrays containing id and visited
*/
function _node_in_list($node,$list)
{
foreach($list as $a_node) {
if($node['id'] == $a_node['id']) return true;
}
return false;
}
/*!
\private
Normalizes an activity name
*/
function _normalize_name($name)
{
$name = str_replace(" ","_",$name);
$name = preg_replace("/[^A-Za-z_]/",'',$name);
return $name;
}
/*!
\private
Returns normalized name of an activity
*/
function _get_normalized_name($activityId)
{
return $this->getOne("select normalized_name from ".GALAXIA_TABLE_PREFIX."activities where activityId=$activityId");
}
/*!
\private
Labels nodes
*/
function _label_nodes($pId)
{
///an empty list of nodes starts the process
$nodes = Array();
// the end activity id
$endId = $this->getOne("select activityId from ".GALAXIA_TABLE_PREFIX."activities where pId=$pId and type='end'");
// and the number of total nodes (=activities)
$cant = $this->getOne("select count(*) from ".GALAXIA_TABLE_PREFIX."activities where pId=$pId");
$nodes[] = $endId;
$label = $cant;
$num = $cant;
$query = "update ".GALAXIA_TABLE_PREFIX."activities set flowNum=$cant+1 where pId=$pId";
$this->query($query);
$seen = array();
while(count($nodes)) {
$newnodes = Array();
foreach($nodes as $node) {
// avoid endless loops
if (isset($seen[$node])) continue;
$seen[$node] = 1;
$query = "update ".GALAXIA_TABLE_PREFIX."activities set flowNum=$num where activityId=$node";
$this->query($query);
$query = "select actFromId from ".GALAXIA_TABLE_PREFIX."transitions where actToId=".$node;
$result = $this->query($query);
$ret = Array();
while($res = $result->fetchRow()) {
$newnodes[] = $res['actFromId'];
}
}
$num--;
$nodes=Array();
$nodes=$newnodes;
}
$min = $this->getOne("select min(flowNum) from ".GALAXIA_TABLE_PREFIX."activities where pId=$pId");
$query = "update ".GALAXIA_TABLE_PREFIX."activities set flowNum=flowNum-$min where pId=$pId";
$this->query($query);
//$query = "update ".GALAXIA_TABLE_PREFIX."activities set flowNum=0 where flowNum=$cant+1";
//$this->query($query);
}
}
?>

View File

@ -0,0 +1,22 @@
<?php
include_once(GALAXIA_LIBRARY.'/src/common/Base.php');
//!! Abstract class representing the base of the API
//! An abstract class representing the API base
/*!
This class is derived by all the API classes so they get the
database connection, database methods and the Observable interface.
*/
class BaseManager extends Base {
// Constructor receiving an ADODB database object.
function BaseManager($db)
{
if(!$db) {
die("Invalid db object passed to BaseManager constructor");
}
$this->db = $db;
}
} //end of class
?>

View File

@ -0,0 +1,465 @@
<?php
//
// +----------------------------------------------------------------------+
// | PEAR :: Image :: GraphViz |
// +----------------------------------------------------------------------+
// | Copyright (c) 2002 Sebastian Bergmann <sb@sebastian-bergmann.de> and |
// | Dr. Volker Göbbels <vmg@arachnion.de>. |
// +----------------------------------------------------------------------+
// | This source file is subject to version 3.00 of the PHP License, |
// | that is available at http://www.php.net/license/3_0.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
//
// $Id$
//
/**
* PEAR::Image_GraphViz
*
* Purpose
*
* Allows for the creation of and the work with directed
* and undirected graphs and their visualization with
* AT&T's GraphViz tools. These can be found at
* http://www.research.att.com/sw/tools/graphviz/
*
* Example
*
* require_once 'Image/GraphViz.php';
* $graph = new Image_GraphViz();
*
* $graph->addNode('Node1', array('URL' => 'http://link1',
* 'label' => 'This is a label',
* 'shape' => 'box'
* )
* );
* $graph->addNode('Node2', array('URL' => 'http://link2',
* 'fontsize' => '14'
* )
* );
* $graph->addNode('Node3', array('URL' => 'http://link3',
* 'fontsize' => '20'
* )
* );
*
* $graph->addEdge(array('Node1' => 'Node2'), array('label' => 'Edge Label'));
* $graph->addEdge(array('Node1' => 'Node2'), array('color' => 'red'));
*
* $graph->image();
*
* @author Sebastian Bergmann <sb@sebastian-bergmann.de>
* Dr. Volker Göbbels <vmg@arachnion.de>
* @package Image
*/
class Process_GraphViz {
/**
* Path to GraphViz/dot command
*
* @var string
*/
var $dotCommand = 'dot';
var $pid;
/**
* Path to GraphViz/neato command
*
* @var string
*/
var $neatoCommand = 'neato';
/**
* Representation of the graph
*
* @var array
*/
var $graph;
/**
* Constructor
*
* @param boolean Directed (true) or undirected (false) graph.
* @param array Attributes of the graph
* @access public
*/
function Process_GraphViz($directed = true, $attributes = array()) {
$this->setDirected($directed);
$this->setAttributes($attributes);
if (defined('GRAPHVIZ_BIN_DIR') && GRAPHVIZ_BIN_DIR) {
$this->dotCommand = GRAPHVIZ_BIN_DIR.'/'.$this->dotCommand;
$this->neatoCommand = GRAPHVIZ_BIN_DIR.'/'.$this->neatoCommand;
}
}
function set_pid($pid)
{
$this->pid = $pid;
}
/**
* Output image of the graph in a given format.
*
* @param string Format of the output image.
* This may be one of the formats supported by GraphViz.
* @access public
*/
function image($format = 'png') {
if ($file = $this->saveParsedGraph()) {
$outputfile = $file . '.' . $format;
$outputfile2 = $file . '.' . 'map';
$command = $this->graph['directed'] ? $this->dotCommand : $this->neatoCommand;
$command .= " -T$format -o$outputfile $file";
@`$command`;
$command = $this->dotCommand;
$command.= " -Tcmap -o$outputfile2 $file";
@`$command`;
$fr = fopen($outputfile2,"r");
$map = fread($fr,filesize($outputfile2));
fclose($fr);
@unlink($file);
switch ($format) {
case 'gif':
case 'jpg':
case 'png':
case 'svg':
case 'wbmp': {
header('Content-Type: image/' . $format);
}
break;
case 'pdf': {
header('Content-Type: application/pdf');
}
break;
}
header('Content-Length: ' . filesize($outputfile));
$fp = fopen($outputfile, 'rb');
if ($fp) {
echo fread($fp, filesize($outputfile));
fclose($fp);
@unlink($outputfile);
}
@unlink($outputfile2);
return $map;
}
}
function image_and_map($format = 'png') {
if ($file = $this->saveParsedGraph()) {
$outputfile = $file . '.' . $format;
$outputfile2 = $file . '.' . 'map';
if(!isset($this->graph['directed'])) $this->graph['directed']=true;
$command = $this->graph['directed'] ? $this->dotCommand : $this->neatoCommand;
$command .= " -T$format -o $outputfile $file";
@`$command`;
$command = $this->dotCommand;
$command.= " -Tcmap -o $outputfile2 $file";
@`$command`;
@unlink($file);
return true;
}
}
function map() {
if ($file = $this->saveParsedGraph()) {
$outputfile2 = $file . '.' . 'map';
$command = $this->dotCommand;
$command.= " -Tcmap -o$outputfile2 $file";
@`$command`;
$fr = fopen($outputfile2,"r");
$map = fread($fr,filesize($outputfile2));
fclose($fr);
@unlink($outputfile2);
@unlink($file);
return $map;
}
}
/**
* Add a cluster to the graph.
*
* @param string ID.
* @param array Title.
* @access public
*/
function addCluster($id, $title) {
$this->graph['clusters'][$id] = $title;
}
/**
* Add a note to the graph.
*
* @param string Name of the node.
* @param array Attributes of the node.
* @param string Group of the node.
* @access public
*/
function addNode($name, $attributes = array(), $group = 'default') {
$this->graph['nodes'][$group][$name] = $attributes;
}
/**
* Remove a node from the graph.
*
* @param Name of the node to be removed.
* @access public
*/
function removeNode($name, $group = 'default') {
if (isset($this->graph['nodes'][$group][$name])) {
unset($this->graph['nodes'][$group][$name]);
}
}
/**
* Add an edge to the graph.
*
* @param array Start and End node of the edge.
* @param array Attributes of the edge.
* @access public
*/
function addEdge($edge, $attributes = array()) {
if (is_array($edge)) {
$from = key($edge);
$to = $edge[$from];
$id = $from . '_' . $to;
if (!isset($this->graph['edges'][$id])) {
$this->graph['edges'][$id] = $edge;
} else {
$this->graph['edges'][$id] = array_merge(
$this->graph['edges'][$id],
$edge
);
}
if (is_array($attributes)) {
if (!isset($this->graph['edgeAttributes'][$id])) {
$this->graph['edgeAttributes'][$id] = $attributes;
} else {
$this->graph['edgeAttributes'][$id] = array_merge(
$this->graph['edgeAttributes'][$id],
$attributes
);
}
}
}
}
/**
* Remove an edge from the graph.
*
* @param array Start and End node of the edge to be removed.
* @access public
*/
function removeEdge($edge) {
if (is_array($edge)) {
$from = key($edge);
$to = $edge[$from];
$id = $from . '_' . $to;
if (isset($this->graph['edges'][$id])) {
unset($this->graph['edges'][$id]);
}
if (isset($this->graph['edgeAttributes'][$id])) {
unset($this->graph['edgeAttributes'][$id]);
}
}
}
/**
* Add attributes to the graph.
*
* @param array Attributes to be added to the graph.
* @access public
*/
function addAttributes($attributes) {
if (is_array($attributes)) {
$this->graph['attributes'] = array_merge(
$this->graph['attributes'],
$attributes
);
}
}
/**
* Set attributes of the graph.
*
* @param array Attributes to be set for the graph.
* @access public
*/
function setAttributes($attributes) {
if (is_array($attributes)) {
$this->graph['attributes'] = $attributes;
}
}
/**
* Set directed/undirected flag for the graph.
*
* @param boolean Directed (true) or undirected (false) graph.
* @access public
*/
function setDirected($directed) {
if (is_bool($directed)) {
$this->graph['directed'] = $directed;
}
}
/**
* Load graph from file.
*
* @param string File to load graph from.
* @access public
*/
function load($file) {
if ($serialized_graph = implode('', @file($file))) {
$this->graph = unserialize($serialized_graph);
}
}
/**
* Save graph to file.
*
* @param string File to save the graph to.
* @return mixed File the graph was saved to, false on failure.
* @access public
*/
function save($file = '') {
$serialized_graph = serialize($this->graph);
if (empty($file)) {
$file = tempnam('temp', 'graph_');
}
if ($fp = @fopen($file, 'w')) {
@fputs($fp, $serialized_graph);
@fclose($fp);
return $file;
}
return false;
}
/**
* Parse the graph into GraphViz markup.
*
* @return string GraphViz markup
* @access public
*/
function parse() {
$parsedGraph = "digraph G {\n";
if (isset($this->graph['attributes'])) {
foreach ($this->graph['attributes'] as $key => $value) {
$attributeList[] = $key . '="' . $value . '"';
}
if (!empty($attributeList)) {
$parsedGraph .= implode(',', $attributeList) . ";\n";
}
}
if (isset($this->graph['nodes'])) {
foreach($this->graph['nodes'] as $group => $nodes) {
if ($group != 'default') {
$parsedGraph .= sprintf(
"subgraph \"cluster_%s\" {\nlabel=\"%s\";\n",
$group,
isset($this->graph['clusters'][$group]) ? $this->graph['clusters'][$group] : ''
);
}
foreach($nodes as $node => $attributes) {
unset($attributeList);
foreach($attributes as $key => $value) {
$attributeList[] = $key . '="' . $value . '"';
}
if (!empty($attributeList)) {
$parsedGraph .= sprintf(
"\"%s\" [ %s ];\n",
addslashes(stripslashes($node)),
implode(',', $attributeList)
);
}
}
if ($group != 'default') {
$parsedGraph .= "}\n";
}
}
}
if (isset($this->graph['edges'])) {
foreach($this->graph['edges'] as $label => $node) {
unset($attributeList);
$from = key($node);
$to = $node[$from];
foreach($this->graph['edgeAttributes'][$label] as $key => $value) {
$attributeList[] = $key . '="' . $value . '"';
}
$parsedGraph .= sprintf(
'"%s" -> "%s"',
addslashes(stripslashes($from)),
addslashes(stripslashes($to))
);
if (!empty($attributeList)) {
$parsedGraph .= sprintf(
' [ %s ]',
implode(',', $attributeList)
);
}
$parsedGraph .= ";\n";
}
}
return $parsedGraph . "}\n";
}
/**
* Save GraphViz markup to file.
*
* @param string File to write the GraphViz markup to.
* @return mixed File to which the GraphViz markup was
* written, false on failure.
* @access public
*/
function saveParsedGraph($file = '') {
$parsedGraph = $this->parse();
if (!empty($parsedGraph)) {
$file = GALAXIA_PROCESSES.'/'.$this->pid.'/graph/'.$this->pid;
if ($fp = @fopen($file, 'w')) {
@fputs($fp, $parsedGraph);
@fclose($fp);
return $file;
}
}
return false;
}
}
?>

View File

@ -0,0 +1,86 @@
<?php
include_once(GALAXIA_LIBRARY.'/src/ProcessManager/BaseManager.php');
//!! InstanceManager
//! A class to maniplate instances
/*!
This class is used to add,remove,modify and list
instances.
*/
class InstanceManager extends BaseManager {
/*!
Constructor takes a PEAR::Db object to be used
to manipulate roles in the database.
*/
function InstanceManager($db)
{
if(!$db) {
die("Invalid db object passed to InstanceManager constructor");
}
$this->db = $db;
}
function get_instance_activities($iid)
{
$query = "select ga.type,ga.isInteractive,ga.isAutoRouted,gi.pId,ga.activityId,ga.name,gi.instanceId,gi.status,gia.activityId,gia.user,gi.started,gia.status as actstatus from ".GALAXIA_TABLE_PREFIX."activities ga,".GALAXIA_TABLE_PREFIX."instances gi,".GALAXIA_TABLE_PREFIX."instance_activities gia where ga.activityId=gia.activityId and gi.instanceId=gia.instanceId and gi.instanceId=$iid";
$result = $this->query($query);
$ret = Array();
while($res = $result->fetchRow()) {
// Number of active instances
$ret[] = $res;
}
return $ret;
}
function get_instance($iid)
{
$query = "select * from ".GALAXIA_TABLE_PREFIX."instances gi where instanceId=$iid";
$result = $this->query($query);
$res = $result->fetchRow();
$res['workitems']=$this->getOne("select count(*) from ".GALAXIA_TABLE_PREFIX."workitems where instanceId=$iid");
return $res;
}
function get_instance_properties($iid)
{
$prop = unserialize($this->getOne("select properties from ".GALAXIA_TABLE_PREFIX."instances gi where instanceId=$iid"));
return $prop;
}
function set_instance_properties($iid,&$prop)
{
$props = addslashes(serialize($prop));
$query = "update ".GALAXIA_TABLE_PREFIX."instances set properties='$props' where instanceId=$iid";
$this->query($query);
}
function set_instance_owner($iid,$owner)
{
$query = "update ".GALAXIA_TABLE_PREFIX."instances set owner='$owner' where instanceId=$iid";
$this->query($query);
}
function set_instance_status($iid,$status)
{
$query = "update ".GALAXIA_TABLE_PREFIX."instances set status='$status' where instanceId=$iid";
$this->query($query);
}
function set_instance_destination($iid,$activityId)
{
$query = "delete from ".GALAXIA_TABLE_PREFIX."instance_activities where instanceId=$iid";
$this->query($query);
$query = "insert into ".GALAXIA_TABLE_PREFIX."instance_activities(instanceId,activityId,user,status)
values($iid,$activityId,'*','running')";
$this->query($query);
}
function set_instance_user($iid,$activityId,$user)
{
$query = "update ".GALAXIA_TABLE_PREFIX."instance_activities set user='$user', status='running' where instanceId=$iid and activityId=$activityId";
$this->query($query);
}
}
?>

View File

@ -0,0 +1,720 @@
<?php
include_once(GALAXIA_LIBRARY.'/src/ProcessManager/BaseManager.php');
//!! ProcessManager
//! A class to maniplate processes.
/*!
This class is used to add,remove,modify and list
processes.
*/
class ProcessManager extends BaseManager {
var $parser;
var $tree;
var $current;
var $buffer;
/*!
Constructor takes a PEAR::Db object to be used
to manipulate roles in the database.
*/
function ProcessManager($db)
{
if(!$db) {
die("Invalid db object passed to ProcessManager constructor");
}
$this->db = $db;
}
/*!
Sets a process as active
*/
function activate_process($pId)
{
$query = "update ".GALAXIA_TABLE_PREFIX."processes set isActive='y' where pId=$pId";
$this->query($query);
$msg = sprintf(tra('Process %d has been activated'),$pId);
$this->notify_all(3,$msg);
}
/*!
De-activates a process
*/
function deactivate_process($pId)
{
$query = "update ".GALAXIA_TABLE_PREFIX."processes set isActive='n' where pId=$pId";
$this->query($query);
$msg = sprintf(tra('Process %d has been deactivated'),$pId);
$this->notify_all(3,$msg);
}
/*!
Creates an XML representation of a process.
*/
function serialize_process($pId)
{
// <process>
$out = '<process>'."\n";
$proc_info = $this->get_process($pId);
$procname = $proc_info['normalized_name'];
$out.= ' <name>'.htmlspecialchars($proc_info['name']).'</name>'."\n";
$out.= ' <isValid>'.htmlspecialchars($proc_info['isValid']).'</isValid>'."\n";
$out.= ' <version>'.htmlspecialchars($proc_info['version']).'</version>'."\n";
$out.= ' <isActive>'.htmlspecialchars($proc_info['isActive']).'</isActive>'."\n";
$out.=' <description>'.htmlspecialchars($proc_info['description']).'</description>'."\n";
$out.= ' <lastModif>'.date("d/m/Y [h:i:s]",$proc_info['lastModif']).'</lastModif>'."\n";
$out.= ' <sharedCode><![CDATA[';
$fp=fopen(GALAXIA_PROCESSES."/$procname/code/shared.php","r");
while(!feof($fp)) {
$line=fread($fp,8192);
$out.=$line;
}
fclose($fp);
$out.= ' ]]></sharedCode>'."\n";
// Now loop over activities
$query = "select * from ".GALAXIA_TABLE_PREFIX."activities where pId=$pId";
$result = $this->query($query);
$out.=' <activities>'."\n";
$am = new ActivityManager($this->db);
while($res = $result->fetchRow()) {
$name = $res['normalized_name'];
$out.=' <activity>'."\n";
$out.=' <name>'.htmlspecialchars($res['name']).'</name>'."\n";
$out.=' <type>'.htmlspecialchars($res['type']).'</type>'."\n";
$out.=' <description>'.htmlspecialchars($res['description']).'</description>'."\n";
$out.=' <lastModif>'.date("d/m/Y [h:i:s]",$res['lastModif']).'</lastModif>'."\n";
$out.=' <isInteractive>'.$res['isInteractive'].'</isInteractive>'."\n";
$out.=' <isAutoRouted>'.$res['isAutoRouted'].'</isAutoRouted>'."\n";
$out.=' <roles>'."\n";
$roles = $am->get_activity_roles($res['activityId']);
foreach($roles as $role) {
$out.=' <role>'.htmlspecialchars($role['name']).'</role>'."\n";
}
$out.=' </roles>'."\n";
$out.=' <code><![CDATA[';
$fp=fopen(GALAXIA_PROCESSES."/$procname/code/activities/$name.php","r");
while(!feof($fp)) {
$line=fread($fp,8192);
$out.=$line;
}
fclose($fp);
$out.=' ]]></code>';
if($res['isInteractive']=='y') {
$out.=' <template><![CDATA[';
$fp=fopen(GALAXIA_PROCESSES."/$procname/code/templates/$name.tpl","r");
while(!feof($fp)) {
$line=fread($fp,8192);
$out.=$line;
}
fclose($fp);
$out.=' ]]></template>';
}
$out.=' </activity>'."\n";
}
$out.=' </activities>'."\n";
$out.=' <transitions>'."\n";
$transitions = $am->get_process_transitions($pId);
foreach($transitions as $tran) {
$out.=' <transition>'."\n";
$out.=' <from>'.htmlspecialchars($tran['actFromName']).'</from>'."\n";
$out.=' <to>'.htmlspecialchars($tran['actToName']).'</to>'."\n";
$out.=' </transition>'."\n";
}
$out.=' </transitions>'."\n";
$out.= '</process>'."\n";
//$fp = fopen(GALAXIA_PROCESSES."/$procname/$procname.xml","w");
//fwrite($fp,$out);
//fclose($fp);
return $out;
}
/*!
Creates a process PHP data structure from its XML
representation
*/
function unserialize_process($xml)
{
// Create SAX parser assign this object as base for handlers
// handlers are private methods defined below.
// keep contexts and parse
$this->parser = xml_parser_create();
xml_parser_set_option($this->parser,XML_OPTION_CASE_FOLDING,0);
xml_set_object($this->parser, $this);
xml_set_element_handler($this->parser, "_start_element_handler", "_end_element_handler");
xml_set_character_data_handler($this->parser, "_data_handler");
$aux=Array(
'name'=>'root',
'children'=>Array(),
'parent' => 0,
'data'=>''
);
$this->tree[0]=$aux;
$this->current=0;
if (!xml_parse($this->parser, $xml, true)) {
$error = sprintf("XML error: %s at line %d",
xml_error_string(xml_get_error_code($this->parser)),
xml_get_current_line_number($this->parser));
trigger_error($error,E_USER_WARNING);
}
xml_parser_free($this->parser);
// Now that we have the tree we can do interesting things
//print_r($this->tree);
$process=Array();
$activities=Array();
$transitions=Array();
for($i=0;$i<count($this->tree[1]['children']);$i++) {
// Process attributes
$z=$this->tree[1]['children'][$i];
$name = trim($this->tree[$z]['name']);
if($name=='activities') {
for($j=0;$j<count($this->tree[$z]['children']);$j++) {
$z2 = $this->tree[$z]['children'][$j];
// this is an activity $name = $this->tree[$z2]['name'];
if($this->tree[$z2]['name']=='activity') {
for($k=0;$k<count($this->tree[$z2]['children']);$k++) {
$z3 = $this->tree[$z2]['children'][$k];
$name = trim($this->tree[$z3]['name']);
$value= trim($this->tree[$z3]['data']);
if($name=='roles') {
$roles=Array();
for($l=0;$l<count($this->tree[$z3]['children']);$l++) {
$z4 = $this->tree[$z3]['children'][$l];
$name = trim($this->tree[$z4]['name']);
$data = trim($this->tree[$z4]['data']);
$roles[]=$data;
}
} else {
$aux[$name]=$value;
//print("$name:$value<br/>");
}
}
$aux['roles']=$roles;
$activities[]=$aux;
}
}
} elseif($name=='transitions') {
for($j=0;$j<count($this->tree[$z]['children']);$j++) {
$z2 = $this->tree[$z]['children'][$j];
// this is an activity $name = $this->tree[$z2]['name'];
if($this->tree[$z2]['name']=='transition') {
for($k=0;$k<count($this->tree[$z2]['children']);$k++) {
$z3 = $this->tree[$z2]['children'][$k];
$name = trim($this->tree[$z3]['name']);
$value= trim($this->tree[$z3]['data']);
if($name == 'from' || $name == 'to') {
$aux[$name]=$value;
}
}
}
$transitions[] = $aux;
}
} else {
$value = trim($this->tree[$z]['data']);
//print("$name is $value<br/>");
$process[$name]=$value;
}
}
$process['activities']=$activities;
$process['transitions']=$transitions;
return $process;
}
/*!
Creates a process from the process data structure, if you want to
convert an XML to a process then use first unserialize_process
and then this method.
*/
function import_process($data)
{
//Now the show begins
$am = new ActivityManager($this->db);
$rm = new RoleManager($this->db);
// First create the process
$vars = Array(
'name' => $data['name'],
'version' => $data['version'],
'description' => $data['description'],
'lastModif' => $data['lastModif'],
'isActive' => $data['isActive'],
'isValid' => $data['isValid']
);
$pid = $this->replace_process(0,$vars,false);
//Put the shared code
$proc_info = $this->get_process($pid);
$procname = $proc_info['normalized_name'];
$fp = fopen(GALAXIA_PROCESSES."/$procname/code/shared.php","w");
fwrite($fp,$data['sharedCode']);
fclose($fp);
$actids = Array();
// Foreach activity create activities
foreach($data['activities'] as $activity) {
$vars = Array(
'name' => $activity['name'],
'description' => $activity['description'],
'type' => $activity['type'],
'lastModif' => $activity['lastModif'],
'isInteractive' => $activity['isInteractive'],
'isAutoRouted' => $activity['isAutoRouted']
);
$actname=$am->_normalize_name($activity['name']);
$actid = $am->replace_activity($pid,0,$vars);
$fp = fopen(GALAXIA_PROCESSES."/$procname/code/activities/$actname".'.php',"w");
fwrite($fp,$activity['code']);
fclose($fp);
if($activity['isInteractive']=='y') {
$fp = fopen(GALAXIA_PROCESSES."/$procname/code/templates/$actname".'.tpl',"w");
fwrite($fp,$activity['template']);
fclose($fp);
}
$actids[$activity['name']] = $am->_get_activity_id_by_name($pid,$activity['name']);
$actname = $am->_normalize_name($activity['name']);
$now = date("U");
foreach($activity['roles'] as $role) {
$vars = Array(
'name' => $role,
'description' => $role,
'lastModif' => $now,
);
if(!$rm->role_name_exists($pid,$role)) {
$rid=$rm->replace_role($pid,0,$vars);
} else {
$rid = $rm->get_role_id($pid,$role);
}
if($actid && $rid) {
$am->add_activity_role($actid,$rid);
}
}
}
foreach($data['transitions'] as $tran) {
$am->add_transition($pid,$actids[$tran['from']],$actids[$tran['to']]);
}
// FIXME: recompile activities seems to be needed here
foreach ($actids as $name => $actid) {
$am->compile_activity($pid,$actid);
}
// create a graph for the new process
$am->build_process_graph($pid);
unset($am);
unset($rm);
$msg = sprintf(tra('Process %s %s imported'),$proc_info['name'],$proc_info['version']);
$this->notify_all(2,$msg);
}
/*!
Creates a new process based on an existing process
changing the process version. By default the process
is created as an unactive process and the version is
by default a minor version of the process.
*/
///\todo copy process activities and so
function new_process_version($pId, $minor=true)
{
$oldpid = $pId;
$proc_info = $this->get_process($pId);
$name = $proc_info['name'];
if(!$proc_info) return false;
// Now update the version
$version = $this->_new_version($proc_info['version'],$minor);
while($this->getOne("select count(*) from ".GALAXIA_TABLE_PREFIX."processes where name='$name' and version='$version'")) {
$version = $this->_new_version($version,$minor);
}
// Make new versions unactive
$proc_info['version'] = $version;
$proc_info['isActive'] = 'n';
// create a new process, but don't create start/end activities
$pid = $this->replace_process(0, $proc_info, false);
// And here copy all the activities & so
$am = new ActivityManager($this->db);
$query = "select * from ".GALAXIA_TABLE_PREFIX."activities where pId=$oldpid";
$result = $this->query($query);
$newaid = array();
while($res = $result->fetchRow()) {
$oldaid = $res['activityId'];
$newaid[$oldaid] = $am->replace_activity($pid,0,$res);
}
// create transitions
$query = "select * from ".GALAXIA_TABLE_PREFIX."transitions where pId=$oldpid";
$result = $this->query($query);
while($res = $result->fetchRow()) {
if (empty($newaid[$res['actFromId']]) || empty($newaid[$res['actToId']])) {
continue;
}
$am->add_transition($pid,$newaid[$res['actFromId']],$newaid[$res['actToId']]);
}
// create roles
$rm = new RoleManager($this->db);
$query = "select * from ".GALAXIA_TABLE_PREFIX."roles where pId=$oldpid";
$result = $this->query($query);
$newrid = array();
while($res = $result->fetchRow()) {
if(!$rm->role_name_exists($pid,$res['name'])) {
$rid=$rm->replace_role($pid,0,$res);
} else {
$rid = $rm->get_role_id($pid,$res['name']);
}
$newrid[$res['roleId']] = $rid;
}
// map users to roles
if (count($newrid) > 0) {
$query = "select * from ".GALAXIA_TABLE_PREFIX."user_roles where pId=$oldpid";
$result = $this->query($query);
while($res = $result->fetchRow()) {
if (empty($newrid[$res['roleId']])) {
continue;
}
$rm->map_user_to_role($pid,$res['user'],$newrid[$res['roleId']]);
}
}
// add roles to activities
if (count($newaid) > 0 && count($newrid ) > 0) {
$query = "select * from ".GALAXIA_TABLE_PREFIX."activity_roles where activityId in (" . join(', ',array_keys($newaid)) . ")";
$result = $this->query($query);
while($res = $result->fetchRow()) {
if (empty($newaid[$res['activityId']]) || empty($newrid[$res['roleId']])) {
continue;
}
$am->add_activity_role($newaid[$res['activityId']],$newrid[$res['roleId']]);
}
}
//Now since we are copying a process we should copy
//the old directory structure to the new directory
$oldname = $proc_info['normalized_name'];
$newname = $this->_get_normalized_name($pid);
$this->_rec_copy(GALAXIA_PROCESSES."/$oldname",GALAXIA_PROCESSES."/$newname");
// create a graph for the new process
$am->build_process_graph($pid);
return $pid;
}
/*!
This function can be used to check if a process name exists, note that
this is NOT used by replace_process since that function can be used to
create new versions of an existing process. The application must use this
method to ensure that processes have unique names.
*/
function process_name_exists($name,$version)
{
$name = addslashes($this->_normalize_name($name,$version));
return $this->getOne("select count(*) from ".GALAXIA_TABLE_PREFIX."processes where normalized_name='$name'");
}
/*!
Gets a process by pId. Fields are returned as an asociative array
*/
function get_process($pId)
{
$query = "select * from ".GALAXIA_TABLE_PREFIX."processes where pId=$pId";
$result = $this->query($query);
if(!$result->numRows()) return false;
$res = $result->fetchRow();
return $res;
}
/*!
Lists processes (all processes)
*/
function list_processes($offset,$maxRecords,$sort_mode,$find,$where='')
{
$sort_mode = $this->convert_sortmode($sort_mode);
if($find) {
$findesc = '%'.$find.'%';
$mid=" where ((name like ?) or (description like ?))";
$bindvars = array($findesc,$findesc);
} else {
$mid="";
$bindvars = array();
}
if($where) {
if($mid) {
$mid.= " and ($where) ";
} else {
$mid.= " where ($where) ";
}
}
$query = "select * from ".GALAXIA_TABLE_PREFIX."processes $mid order by $sort_mode";
$query_cant = "select count(*) from ".GALAXIA_TABLE_PREFIX."processes $mid";
$result = $this->query($query,$bindvars,$maxRecords,$offset);
$cant = $this->getOne($query_cant,$bindvars);
$ret = Array();
while($res = $result->fetchRow()) {
$ret[] = $res;
}
$retval = Array();
$retval["data"] = $ret;
$retval["cant"] = $cant;
return $retval;
}
/*!
Marks a process as an invalid process
*/
function invalidate_process($pid)
{
$query = "update ".GALAXIA_TABLE_PREFIX."processes set isValid='n' where pId=$pid";
$this->query($query);
}
/*!
Removes a process by pId
*/
function remove_process($pId)
{
$this->deactivate_process($pId);
$name = $this->_get_normalized_name($pId);
$aM = new ActivityManager($this->db);
// Remove process activities
$query = "select activityId from ".GALAXIA_TABLE_PREFIX."activities where pId=$pId";
$result = $this->query($query);
while($res = $result->fetchRow()) {
$aM->remove_activity($pId,$res['activityId']);
}
// Remove process roles
$query = "delete from ".GALAXIA_TABLE_PREFIX."roles where pId=$pId";
$this->query($query);
$query = "delete from ".GALAXIA_TABLE_PREFIX."user_roles where pId=$pId";
$this->query($query);
// Remove the directory structure
if (!empty($name) && is_dir(GALAXIA_PROCESSES."/$name")) {
$this->_remove_directory(GALAXIA_PROCESSES."/$name",true);
}
if (GALAXIA_TEMPLATES && !empty($name) && is_dir(GALAXIA_TEMPLATES."/$name")) {
$this->_remove_directory(GALAXIA_TEMPLATES."/$name",true);
}
// And finally remove the proc
$query = "delete from ".GALAXIA_TABLE_PREFIX."processes where pId=$pId";
$this->query($query);
$msg = sprintf(tra('Process %s removed'),$name);
$this->notify_all(5,$msg);
return true;
}
/*!
Updates or inserts a new process in the database, $vars is an asociative
array containing the fields to update or to insert as needed.
$pId is the processId
*/
function replace_process($pId, $vars, $create = true)
{
$TABLE_NAME = GALAXIA_TABLE_PREFIX."processes";
$now = date("U");
$vars['lastModif']=$now;
$vars['normalized_name'] = $this->_normalize_name($vars['name'],$vars['version']);
foreach($vars as $key=>$value)
{
$vars[$key]=addslashes($value);
}
if($pId) {
// update mode
$old_proc = $this->get_process($pId);
$first = true;
$query ="update $TABLE_NAME set";
foreach($vars as $key=>$value) {
if(!$first) $query.= ',';
if(!is_numeric($value)||strstr($value,'.')) $value="'".$value."'";
$query.= " $key=$value ";
$first = false;
}
$query .= " where pId=$pId ";
$this->query($query);
// Note that if the name is being changed then
// the directory has to be renamed!
$oldname = $old_proc['normalized_name'];
$newname = $vars['normalized_name'];
if ($newname != $oldname) {
rename(GALAXIA_PROCESSES."/$oldname",GALAXIA_PROCESSES."/$newname");
}
$msg = sprintf(tra('Process %s has been updated'),$vars['name']);
$this->notify_all(3,$msg);
} else {
unset($vars['pId']);
// insert mode
$name = $this->_normalize_name($vars['name'],$vars['version']);
$this->_create_directory_structure($name);
$first = true;
$query = "insert into $TABLE_NAME(";
foreach(array_keys($vars) as $key) {
if(!$first) $query.= ',';
$query.= "$key";
$first = false;
}
$query .=") values(";
$first = true;
foreach(array_values($vars) as $value) {
if(!$first) $query.= ',';
if(!is_numeric($value)||strstr($value,'.')) $value="'".$value."'";
$query.= "$value";
$first = false;
}
$query .=")";
$this->query($query);
$pId = $this->getOne("select max(pId) from $TABLE_NAME where lastModif=$now");
// Now automatically add a start and end activity
// unless importing ($create = false)
if($create) {
$aM= new ActivityManager($this->db);
$vars1 = Array(
'name' => 'start',
'description' => 'default start activity',
'type' => 'start',
'isInteractive' => 'y',
'isAutoRouted' => 'y'
);
$vars2 = Array(
'name' => 'end',
'description' => 'default end activity',
'type' => 'end',
'isInteractive' => 'n',
'isAutoRouted' => 'y'
);
$aM->replace_activity($pId,0,$vars1);
$aM->replace_activity($pId,0,$vars2);
}
$msg = sprintf(tra('Process %s has been created'),$vars['name']);
$this->notify_all(4,$msg);
}
// Get the id
return $pId;
}
/*!
\private
Gets the normalized name of a process by pid
*/
function _get_normalized_name($pId)
{
$info = $this->get_process($pId);
return $info['normalized_name'];
}
/*!
\private
Normalizes a process name
*/
function _normalize_name($name, $version)
{
$name = $name.'_'.$version;
$name = str_replace(" ","_",$name);
$name = preg_replace("/[^0-9A-Za-z\_]/",'',$name);
return $name;
}
/*!
\private
Generates a new minor version number
*/
function _new_version($version,$minor=true)
{
$parts = explode('.',$version);
if($minor) {
$parts[count($parts)-1]++;
} else {
$parts[0]++;
for ($i = 1; $i < count($parts); $i++) {
$parts[$i] = 0;
}
}
return implode('.',$parts);
}
/*!
\private
Creates directory structure for process
*/
function _create_directory_structure($name)
{
// Create in processes a directory with this name
mkdir(GALAXIA_PROCESSES."/$name",0770);
mkdir(GALAXIA_PROCESSES."/$name/graph",0770);
mkdir(GALAXIA_PROCESSES."/$name/code",0770);
mkdir(GALAXIA_PROCESSES."/$name/compiled",0770);
mkdir(GALAXIA_PROCESSES."/$name/code/activities",0770);
mkdir(GALAXIA_PROCESSES."/$name/code/templates",0770);
if (GALAXIA_TEMPLATES) {
mkdir(GALAXIA_TEMPLATES."/$name",0770);
}
// Create shared file
$fp = fopen(GALAXIA_PROCESSES."/$name/code/shared.php","w");
fwrite($fp,'<'.'?'.'php'."\n".'?'.'>');
fclose($fp);
}
/*!
\private
Removes a directory recursively
*/
function _remove_directory($dir,$rec=false)
{
// Prevent a disaster
if(trim($dir) == '/'|| trim($dir)=='.' || trim($dir)=='templates' || trim($dir)=='templates/') return false;
$h = opendir($dir);
while(($file = readdir($h)) != false) {
if(is_file($dir.'/'.$file)) {
@unlink($dir.'/'.$file);
} else {
if($rec && $file != '.' && $file != '..') {
$this->_remove_directory($dir.'/'.$file, true);
}
}
}
closedir($h);
@rmdir($dir);
@unlink($dir);
}
function _rec_copy($dir1,$dir2)
{
@mkdir($dir2,0777);
$h = opendir($dir1);
while(($file = readdir($h)) !== false) {
if(is_file($dir1.'/'.$file)) {
copy($dir1.'/'.$file,$dir2.'/'.$file);
} else {
if($file != '.' && $file != '..') {
$this->_rec_copy($dir1.'/'.$file, $dir2.'/'.$file);
}
}
}
closedir($h);
}
function _start_element_handler($parser,$element,$attribs)
{
$aux=Array('name'=>$element,
'data'=>'',
'parent' => $this->current,
'children'=>Array());
$i = count($this->tree);
$this->tree[$i] = $aux;
$this->tree[$this->current]['children'][]=$i;
$this->current=$i;
}
function _end_element_handler($parser,$element)
{
//when a tag ends put text
$this->tree[$this->current]['data']=$this->buffer;
$this->buffer='';
$this->current=$this->tree[$this->current]['parent'];
}
function _data_handler($parser,$data)
{
$this->buffer.=$data;
}
}
?>

View File

@ -0,0 +1,213 @@
<?php
include_once(GALAXIA_LIBRARY.'/src/ProcessManager/BaseManager.php');
//!! RoleManager
//! A class to maniplate roles.
/*!
This class is used to add,remove,modify and list
roles used in the Workflow engine.
Roles are managed in a per-process level, each
role belongs to some process.
*/
/*!TODO
Add a method to check if a role name exists in a process (to be used
to prevent duplicate names)
*/
class RoleManager extends BaseManager {
/*!
Constructor takes a PEAR::Db object to be used
to manipulate roles in the database.
*/
function RoleManager($db)
{
if(!$db) {
die("Invalid db object passed to RoleManager constructor");
}
$this->db = $db;
}
function get_role_id($pid,$name)
{
$name = addslashes($name);
return ($this->getOne("select roleId from ".GALAXIA_TABLE_PREFIX."roles where name='$name' and pId=$pid"));
}
/*!
Gets a role fields are returned as an asociative array
*/
function get_role($pId, $roleId)
{
$query = "select * from `".GALAXIA_TABLE_PREFIX."roles` where `pId`=? and `roleId`=?";
$result = $this->query($query,array($pId, $roleId));
$res = $result->fetchRow();
return $res;
}
/*!
Indicates if a role exists
*/
function role_name_exists($pid,$name)
{
$name = addslashes($name);
return ($this->getOne("select count(*) from ".GALAXIA_TABLE_PREFIX."roles where pId=$pid and name='$name'"));
}
/*!
Maps a user to a role
*/
function map_user_to_role($pId,$user,$roleId)
{
$query = "delete from `".GALAXIA_TABLE_PREFIX."user_roles` where `roleId`=? and `user`=?";
$this->query($query,array($roleId, $user));
$query = "insert into `".GALAXIA_TABLE_PREFIX."user_roles`(`pId`, `user`, `roleId`) values(?,?,?)";
$this->query($query,array($pId,$user,$roleId));
}
/*!
Removes a mapping
*/
function remove_mapping($user,$roleId)
{
$query = "delete from `".GALAXIA_TABLE_PREFIX."user_roles` where `user`=? and `roleId`=?";
$this->query($query,array($user, $roleId));
}
/*!
List mappings
*/
function list_mappings($pId,$offset,$maxRecords,$sort_mode,$find) {
$sort_mode = $this->convert_sortmode($sort_mode);
if($find) {
// no more quoting here - this is done in bind vars already
$findesc = '%'.$find.'%';
$query = "select `name`,`gr`.`roleId`,`user` from `".GALAXIA_TABLE_PREFIX."roles` gr, `".GALAXIA_TABLE_PREFIX."user_roles` gur where `gr`.`roleId`=`gur`.`roleId` and `gur`.`pId`=? and ((`name` like ?) or (`user` like ?) or (`description` like ?)) order by $sort_mode";
$result = $this->query($query,array($pId,$findesc,$findesc,$findesc), $maxRecords, $offset);
$query_cant = "select count(*) from `".GALAXIA_TABLE_PREFIX."roles` gr, `".GALAXIA_TABLE_PREFIX."user_roles` gur where `gr`.`roleId`=`gur`.`roleId` and `gur`.`pId`=? and ((`name` like ?) or (`user` like ?) or (`description` like ?))";
$cant = $this->getOne($query_cant,array($pId,$findesc,$findesc,$findesc));
} else {
$query = "select `name`,`gr`.`roleId`,`user` from `".GALAXIA_TABLE_PREFIX."roles` gr, `".GALAXIA_TABLE_PREFIX."user_roles` gur where `gr`.`roleId`=`gur`.`roleId` and `gur`.`pId`=? order by $sort_mode";
$result = $this->query($query,array($pId), $maxRecords, $offset);
$query_cant = "select count(*) from `".GALAXIA_TABLE_PREFIX."roles` gr, `".GALAXIA_TABLE_PREFIX."user_roles` gur where `gr`.`roleId`=`gur`.`roleId` and `gur`.`pId`=?";
$cant = $this->getOne($query_cant,array($pId));
}
$ret = Array();
while($res = $result->fetchRow()) {
$ret[] = $res;
}
$retval = Array();
$retval["data"] = $ret;
$retval["cant"] = $cant;
return $retval;
}
/*!
Lists roles at a per-process level
*/
function list_roles($pId,$offset,$maxRecords,$sort_mode,$find,$where='')
{
$sort_mode = $this->convert_sortmode($sort_mode);
if($find) {
// no more quoting here - this is done in bind vars already
$findesc = '%'.$find.'%';
$mid=" where pId=? and ((name like ?) or (description like ?))";
$bindvars = array($pId,$findesc,$findesc);
} else {
$mid=" where pId=? ";
$bindvars = array($pId);
}
if($where) {
$mid.= " and ($where) ";
}
$query = "select * from ".GALAXIA_TABLE_PREFIX."roles $mid order by $sort_mode";
$query_cant = "select count(*) from ".GALAXIA_TABLE_PREFIX."roles $mid";
$result = $this->query($query,$bindvars,$maxRecords,$offset);
$cant = $this->getOne($query_cant,$bindvars);
$ret = Array();
while($res = $result->fetchRow()) {
$ret[] = $res;
}
$retval = Array();
$retval["data"] = $ret;
$retval["cant"] = $cant;
return $retval;
}
/*!
Removes a role.
*/
function remove_role($pId, $roleId)
{
$query = "delete from `".GALAXIA_TABLE_PREFIX."roles` where `pId`=? and `roleId`=?";
$this->query($query,array($pId, $roleId));
$query = "delete from `".GALAXIA_TABLE_PREFIX."activity_roles` where `roleId`=?";
$this->query($query,array($roleId));
$query = "delete from `".GALAXIA_TABLE_PREFIX."user_roles` where `roleId`=?";
$this->query($query,array($roleId));
}
/*!
Updates or inserts a new role in the database, $vars is an asociative
array containing the fields to update or to insert as needed.
$pId is the processId
$roleId is the roleId
*/
function replace_role($pId, $roleId, $vars)
{
$TABLE_NAME = GALAXIA_TABLE_PREFIX."roles";
$now = date("U");
$vars['lastModif']=$now;
$vars['pId']=$pId;
foreach($vars as $key=>$value)
{
$vars[$key]=addslashes($value);
}
if($roleId) {
// update mode
$first = true;
$query ="update $TABLE_NAME set";
foreach($vars as $key=>$value) {
if(!$first) $query.= ',';
if(!is_numeric($value)) $value="'".$value."'";
$query.= " $key=$value ";
$first = false;
}
$query .= " where pId=$pId and roleId=$roleId ";
$this->query($query);
} else {
$name = $vars['name'];
if ($this->getOne("select count(*) from ".GALAXIA_TABLE_PREFIX."roles where pId=$pId and name='$name'")) {
return false;
}
unset($vars['roleId']);
// insert mode
$first = true;
$query = "insert into $TABLE_NAME(";
foreach(array_keys($vars) as $key) {
if(!$first) $query.= ',';
$query.= "$key";
$first = false;
}
$query .=") values(";
$first = true;
foreach(array_values($vars) as $value) {
if(!$first) $query.= ',';
if(!is_numeric($value)) $value="'".$value."'";
$query.= "$value";
$first = false;
}
$query .=")";
$this->query($query);
$roleId = $this->getOne("select max(roleId) from $TABLE_NAME where pId=$pId and lastModif=$now");
}
// Get the id
return $roleId;
}
}
?>

View File

@ -0,0 +1,389 @@
<?php
include_once(GALAXIA_LIBRARY.'/src/common/Base.php');
//!! ProcessMonitor
//! ProcessMonitor class
/*!
This class provides methods for use in typical monitoring scripts
*/
class ProcessMonitor extends Base {
function monitor_stats() {
$res = Array();
$res['active_processes'] = $this->getOne("select count(*) from `".GALAXIA_TABLE_PREFIX."processes` where `isActive`=?",array('y'));
$res['processes'] = $this->getOne("select count(*) from `".GALAXIA_TABLE_PREFIX."processes`");
$result = $this->query("select distinct(`pId`) from `".GALAXIA_TABLE_PREFIX."instances` where `status`=?",array('active'));
$res['running_processes'] = $result->numRows();
// get the number of instances per status
$query = "select status, count(*) as num_instances from ".GALAXIA_TABLE_PREFIX."instances group by status";
$result = $this->query($query);
$status = array();
while($info = $result->fetchRow()) {
$status[$info['status']] = $info['num_instances'];
}
$res['active_instances'] = isset($status['active']) ? $status['active'] : 0;
$res['completed_instances'] = isset($status['completed']) ? $status['completed'] : 0;
$res['exception_instances'] = isset($status['exception']) ? $status['exception'] : 0;
$res['aborted_instances'] = isset($status['aborted']) ? $status['aborted'] : 0;
return $res;
}
function update_instance_status($iid,$status) {
$query = "update `".GALAXIA_TABLE_PREFIX."instances` set `status`=? where `instanceId`=?";
$this->query($query,array($status,$iid));
}
function update_instance_activity_status($iid,$activityId,$status) {
$query = "update `".GALAXIA_TABLE_PREFIX."instance_activities` set `status`=? where `instanceId`=? and `activityId`=?";
$this->query($query,array($status,$iid,$activityId));
}
function remove_instance($iid) {
$query = "delete from `".GALAXIA_TABLE_PREFIX."workitems` where `instanceId`=?";
$this->query($query,array($iid));
$query = "delete from `".GALAXIA_TABLE_PREFIX."instance_activities` where `instanceId`=?";
$this->query($query,array($iid));
$query = "delete from `".GALAXIA_TABLE_PREFIX."instances` where `instanceId`=?";
$this->query($query,array($iid));
}
function remove_aborted() {
$query="select `instanceId` from `".GALAXIA_TABLE_PREFIX."instances` where `status`=?";
$result = $this->query($query,array('aborted'));
while($res = $result->fetchRow()) {
$iid = $res['instanceId'];
$query = "delete from `".GALAXIA_TABLE_PREFIX."instance_activities` where `instanceId`=?";
$this->query($query,array($iid));
$query = "delete from `".GALAXIA_TABLE_PREFIX."workitems` where `instanceId`=?";
$this->query($query,array($iid));
}
$query = "delete from `".GALAXIA_TABLE_PREFIX."instances` where `status`=?";
$this->query($query,array('aborted'));
}
function remove_all($pId) {
$query="select `instanceId` from `".GALAXIA_TABLE_PREFIX."instances` where `pId`=?";
$result = $this->query($query,array($pId));
while($res = $result->fetchRow()) {
$iid = $res['instanceId'];
$query = "delete from `".GALAXIA_TABLE_PREFIX."instance_activities` where `instanceId`=?";
$this->query($query,array($iid));
$query = "delete from `".GALAXIA_TABLE_PREFIX."workitems` where `instanceId`=?";
$this->query($query,array($iid));
}
$query = "delete from `".GALAXIA_TABLE_PREFIX."instances` where `pId`=?";
$this->query($query,array($pId));
}
function monitor_list_processes($offset,$maxRecords,$sort_mode,$find,$where='') {
$sort_mode = $this->convert_sortmode($sort_mode);
if($find) {
$findesc = '%'.$find.'%';
$mid=" where ((name like ?) or (description like ?))";
$bindvars = array($findesc,$findesc);
} else {
$mid="";
$bindvars = array();
}
if($where) {
if($mid) {
$mid.= " and ($where) ";
} else {
$mid.= " where ($where) ";
}
}
// get the requested processes
$query = "select * from ".GALAXIA_TABLE_PREFIX."processes $mid order by $sort_mode";
$query_cant = "select count(*) from ".GALAXIA_TABLE_PREFIX."processes $mid";
$result = $this->query($query,$bindvars,$maxRecords,$offset);
$cant = $this->getOne($query_cant,$bindvars);
$ret = Array();
while($res = $result->fetchRow()) {
$pId = $res['pId'];
// Number of active instances
$res['active_instances'] = 0;
// Number of exception instances
$res['exception_instances'] = 0;
// Number of completed instances
$res['completed_instances'] = 0;
// Number of aborted instances
$res['aborted_instances'] = 0;
$res['all_instances'] = 0;
// Number of activities
$res['activities'] = 0;
$ret[$pId] = $res;
}
if (count($ret) < 1) {
$retval = Array();
$retval["data"] = $ret;
$retval["cant"] = $cant;
return $retval;
}
// get number of instances and timing statistics per process and status
$query = "select pId, status, count(*) as num_instances,
min(ended - started) as min_time, avg(ended - started) as avg_time, max(ended - started) as max_time
from ".GALAXIA_TABLE_PREFIX."instances where pId in (" . join(', ', array_keys($ret)) . ") group by pId, status";
$result = $this->query($query);
while($res = $result->fetchRow()) {
$pId = $res['pId'];
if (!isset($ret[$pId])) continue;
switch ($res['status']) {
case 'active':
$ret[$pId]['active_instances'] = $res['num_instances'];
$ret[$pId]['all_instances'] += $res['num_instances'];
break;
case 'completed':
$ret[$pId]['completed_instances'] = $res['num_instances'];
$ret[$pId]['all_instances'] += $res['num_instances'];
$ret[$pId]['duration'] = array('min' => $res['min_time'], 'avg' => $res['avg_time'], 'max' => $res['max_time']);
break;
case 'exception':
$ret[$pId]['exception_instances'] = $res['num_instances'];
$ret[$pId]['all_instances'] += $res['num_instances'];
break;
case 'aborted':
$ret[$pId]['aborted_instances'] = $res['num_instances'];
$ret[$pId]['all_instances'] += $res['num_instances'];
break;
}
}
// get number of activities per process
$query = "select pId, count(*) as num_activities
from ".GALAXIA_TABLE_PREFIX."activities
where pId in (" . join(', ', array_keys($ret)) . ")
group by pId";
$result = $this->query($query);
while($res = $result->fetchRow()) {
$pId = $res['pId'];
if (!isset($ret[$pId])) continue;
$ret[$pId]['activities'] = $res['num_activities'];
}
$retval = Array();
$retval["data"] = $ret;
$retval["cant"] = $cant;
return $retval;
}
function monitor_list_activities($offset,$maxRecords,$sort_mode,$find,$where='') {
$sort_mode = $this->convert_sortmode($sort_mode);
if($find) {
$findesc = '%'.$find.'%';
$mid=" where ((ga.name like ?) or (ga.description like ?))";
$bindvars = array($findesc,$findesc);
} else {
$mid="";
$bindvars = array();
}
if($where) {
$where = preg_replace('/pId/', 'ga.pId', $where);
if($mid) {
$mid.= " and ($where) ";
} else {
$mid.= " where ($where) ";
}
}
$query = "select gp.`name` as `procname`, gp.`version`, ga.*
from ".GALAXIA_TABLE_PREFIX."activities ga
left join ".GALAXIA_TABLE_PREFIX."processes gp on gp.pId=ga.pId
$mid order by $sort_mode";
$query_cant = "select count(*) from ".GALAXIA_TABLE_PREFIX."activities ga $mid";
$result = $this->query($query,$bindvars,$maxRecords,$offset);
$cant = $this->getOne($query_cant,$bindvars);
$ret = Array();
while($res = $result->fetchRow()) {
// Number of active instances
$aid = $res['activityId'];
$res['active_instances']=$this->getOne("select count(gi.instanceId) from ".GALAXIA_TABLE_PREFIX."instances gi,".GALAXIA_TABLE_PREFIX."instance_activities gia where gi.instanceId=gia.instanceId and gia.activitYId=$aid and gi.status='active' and pId=".$res['pId']);
// activities of completed instances are all removed from the instance_activities table for some reason, so we need to look at workitems
$res['completed_instances']=$this->getOne("select count(distinct gi.instanceId) from ".GALAXIA_TABLE_PREFIX."instances gi,".GALAXIA_TABLE_PREFIX."workitems gw where gi.instanceId=gw.instanceId and gw.activityId=$aid and gi.status='completed' and pId=".$res['pId']);
// activities of aborted instances are all removed from the instance_activities table for some reason, so we need to look at workitems
$res['aborted_instances']=$this->getOne("select count(distinct gi.instanceId) from ".GALAXIA_TABLE_PREFIX."instances gi,".GALAXIA_TABLE_PREFIX."workitems gw where gi.instanceId=gw.instanceId and gw.activityId=$aid and gi.status='aborted' and pId=".$res['pId']);
$res['exception_instances']=$this->getOne("select count(gi.instanceId) from ".GALAXIA_TABLE_PREFIX."instances gi,".GALAXIA_TABLE_PREFIX."instance_activities gia where gi.instanceId=gia.instanceId and gia.activityId=$aid and gi.status='exception' and pId=".$res['pId']);
$res['act_running_instances']=$this->getOne("select count(gi.instanceId) from ".GALAXIA_TABLE_PREFIX."instances gi,".GALAXIA_TABLE_PREFIX."instance_activities gia where gi.instanceId=gia.instanceId and gia.activityId=$aid and gia.status='running' and pId=".$res['pId']);
// completed activities are removed from the instance_activities table unless they're part of a split for some reason, so this won't work
// $res['act_completed_instances']=$this->getOne("select count(gi.instanceId) from ".GALAXIA_TABLE_PREFIX."instances gi,".GALAXIA_TABLE_PREFIX."instance_activities gia where gi.instanceId=gia.instanceId and gia.activityId=$aid and gia.status='completed' and pId=".$res['pId']);
$res['act_completed_instances'] = 0;
$ret[$aid] = $res;
}
if (count($ret) < 1) {
$retval = Array();
$retval["data"] = $ret;
$retval["cant"] = $cant;
return $retval;
}
$query = "select activityId, count(distinct instanceId) as num_instances, min(ended - started) as min_time, avg(ended - started) as avg_time, max(ended - started) as max_time
from ".GALAXIA_TABLE_PREFIX."workitems
where activityId in (" . join(', ', array_keys($ret)) . ")
group by activityId";
$result = $this->query($query);
while($res = $result->fetchRow()) {
// Number of active instances
$aid = $res['activityId'];
if (!isset($ret[$aid])) continue;
$ret[$aid]['act_completed_instances'] = $res['num_instances'] - $ret[$aid]['aborted_instances'];
$ret[$aid]['duration'] = array('min' => $res['min_time'], 'avg' => $res['avg_time'], 'max' => $res['max_time']);
}
$retval = Array();
$retval["data"] = $ret;
$retval["cant"] = $cant;
return $retval;
}
function monitor_list_instances($offset,$maxRecords,$sort_mode,$find,$where='',$wherevars='') {
if($find) {
$findesc = $this->qstr('%'.$find.'%');
$mid=" where (`properties` like $findesc)";
} else {
$mid="";
}
if($where) {
if($mid) {
$mid.= " and ($where) ";
} else {
$mid.= " where ($where) ";
}
}
$query = "select gp.`pId`, ga.`isInteractive`, gi.`owner`, gp.`name` as `procname`, gp.`version`, ga.`type`,";
$query.= " ga.`activityId`, ga.`name`, gi.`instanceId`, gi.`status`, gia.`activityId`, gia.`user`, gi.`started`, gi.`ended`, gia.`status` as actstatus ";
$query.=" from `".GALAXIA_TABLE_PREFIX."instances` gi LEFT JOIN `".GALAXIA_TABLE_PREFIX."instance_activities` gia ON gi.`instanceId`=gia.`instanceId` ";
$query.= "LEFT JOIN `".GALAXIA_TABLE_PREFIX."activities` ga ON gia.`activityId` = ga.`activityId` ";
$query.= "LEFT JOIN `".GALAXIA_TABLE_PREFIX."processes` gp ON gp.`pId`=gi.`pId` $mid order by ".$this->convert_sortmode($sort_mode);
$query_cant = "select count(*) from `".GALAXIA_TABLE_PREFIX."instances` gi LEFT JOIN `".GALAXIA_TABLE_PREFIX."instance_activities` gia ON gi.`instanceId`=gia.`instanceId` ";
$query_cant.= "LEFT JOIN `".GALAXIA_TABLE_PREFIX."activities` ga ON gia.`activityId` = ga.`activityId` LEFT JOIN `".GALAXIA_TABLE_PREFIX."processes` gp ON gp.`pId`=gi.`pId` $mid";
$result = $this->query($query,$wherevars,$maxRecords,$offset);
$cant = $this->getOne($query_cant,$wherevars);
$ret = Array();
while($res = $result->fetchRow()) {
$iid = $res['instanceId'];
$res['workitems']=$this->getOne("select count(*) from `".GALAXIA_TABLE_PREFIX."workitems` where `instanceId`=?",array($iid));
$ret[$iid] = $res;
}
$retval = Array();
$retval["data"] = $ret;
$retval["cant"] = $cant;
return $retval;
}
function monitor_list_all_processes($sort_mode = 'name_asc', $where = '') {
if (!empty($where)) {
$where = " where ($where) ";
}
$query = "select `name`,`version`,`pId` from `".GALAXIA_TABLE_PREFIX."processes` $where order by ".$this->convert_sortmode($sort_mode);
$result = $this->query($query);
$ret = Array();
while($res = $result->fetchRow()) {
$pId = $res['pId'];
$ret[$pId] = $res;
}
return $ret;
}
function monitor_list_all_activities($sort_mode = 'name_asc', $where = '') {
if (!empty($where)) {
$where = " where ($where) ";
}
$query = "select `name`,`activityId` from `".GALAXIA_TABLE_PREFIX."activities` $where order by ".$this->convert_sortmode($sort_mode);
$result = $this->query($query);
$ret = Array();
while($res = $result->fetchRow()) {
$aid = $res['activityId'];
$ret[$aid] = $res;
}
return $ret;
}
function monitor_list_statuses() {
$query = "select distinct(`status`) from `".GALAXIA_TABLE_PREFIX."instances`";
$result = $this->query($query);
$ret = Array();
while($res = $result->fetchRow()) {
$ret[] = $res['status'];
}
return $ret;
}
function monitor_list_users() {
$query = "select distinct(`user`) from `".GALAXIA_TABLE_PREFIX."instance_activities`";
$result = $this->query($query);
$ret = Array();
while($res = $result->fetchRow()) {
$ret[] = $res['user'];
}
return $ret;
}
function monitor_list_wi_users() {
$query = "select distinct(`user`) from `".GALAXIA_TABLE_PREFIX."workitems`";
$result = $this->query($query);
$ret = Array();
while($res = $result->fetchRow()) {
$ret[] = $res['user'];
}
return $ret;
}
function monitor_list_owners() {
$query = "select distinct(`owner`) from `".GALAXIA_TABLE_PREFIX."instances`";
$result = $this->query($query);
$ret = Array();
while($res = $result->fetchRow()) {
$ret[] = $res['owner'];
}
return $ret;
}
function monitor_list_activity_types() {
$query = "select distinct(`type`) from `".GALAXIA_TABLE_PREFIX."activities`";
$result = $this->query($query);
$ret = Array();
while($res = $result->fetchRow()) {
$ret[] = $res['type'];
}
return $ret;
}
function monitor_get_workitem($itemId) {
$query = "select gw.`orderId`,ga.`name`,ga.`type`,ga.`isInteractive`,gp.`name` as `procname`,gp.`version`,";
$query.= "gw.`itemId`,gw.`properties`,gw.`user`,`started`,`ended`-`started` as duration ";
$query.= "from `".GALAXIA_TABLE_PREFIX."workitems` gw,`".GALAXIA_TABLE_PREFIX."activities` ga,`".GALAXIA_TABLE_PREFIX."processes` gp where ga.`activityId`=gw.`activityId` and ga.`pId`=gp.`pId` and `itemId`=?";
$result = $this->query($query, array($itemId));
$res = $result->fetchRow();
$res['properties'] = unserialize($res['properties']);
return $res;
}
// List workitems per instance, remove workitem, update_workitem
function monitor_list_workitems($offset,$maxRecords,$sort_mode,$find,$where='',$wherevars=array()) {
$mid = '';
if ($where) {
$mid.= " and ($where) ";
}
if($find) {
$findesc = $this->qstr('%'.$find.'%');
$mid.=" and (`properties` like $findesc)";
}
// TODO: retrieve instance status as well
$query = "select `itemId`,`ended`-`started` as duration,ga.`isInteractive`, ga.`type`,gp.`name` as procname,gp.`version`,ga.`name` as actname,";
$query.= "ga.`activityId`,`instanceId`,`orderId`,`properties`,`started`,`ended`,`user` from `".GALAXIA_TABLE_PREFIX."workitems` gw,`".GALAXIA_TABLE_PREFIX."activities` ga,`".GALAXIA_TABLE_PREFIX."processes` gp ";
$query.= "where gw.`activityId`=ga.`activityId` and ga.`pId`=gp.`pId` $mid order by gp.`pId` desc,".$this->convert_sortmode($sort_mode);
$query_cant = "select count(*) from `".GALAXIA_TABLE_PREFIX."workitems` gw,`".GALAXIA_TABLE_PREFIX."activities` ga,`".GALAXIA_TABLE_PREFIX."processes` gp where gw.`activityId`=ga.`activityId` and ga.`pId`=gp.`pId` $mid";
$result = $this->query($query,$wherevars,$maxRecords,$offset);
$cant = $this->getOne($query_cant,$wherevars);
$ret = Array();
while($res = $result->fetchRow()) {
$itemId = $res['itemId'];
$ret[$itemId] = $res;
}
$retval = Array();
$retval["data"] = $ret;
$retval["cant"] = $cant;
return $retval;
}
}
?>

View File

@ -0,0 +1,130 @@
<?php
include_once(GALAXIA_LIBRARY.'/src/common/Observable.php');
//!! Abstract class representing the base of the API
//! An abstract class representing the API base
/*!
This class is derived by all the API classes so they get the
database connection, database methods and the Observable interface.
*/
class Base extends Observable {
var $db; // The ADODB object used to access the database
var $num_queries = 0;
// Constructor receiving a ADODB database object.
function Base($db)
{
if(!$db) {
die("Invalid db object passed to Base constructor");
}
$this->db = $db;
}
// copied from tikilib.php
function query($query, $values = null, $numrows = -1, $offset = -1, $reporterrors = true) {
$this->convert_query($query);
if ($numrows == -1 && $offset == -1)
$result = $this->db->Execute($query, $values);
else
$result = $this->db->SelectLimit($query, $numrows, $offset, $values);
if (!$result && $reporterrors)
$this->sql_error($query, $values, $result);
$this->num_queries++;
return $result;
}
function getOne($query, $values = null, $reporterrors = true) {
$this->convert_query($query);
$result = $this->db->SelectLimit($query, 1, 0, $values);
if (!$result && $reporterrors)
$this->sql_error($query, $values, $result);
$res = $result->fetchRow();
$this->num_queries++;
if ($res === false)
return (NULL); //simulate pears behaviour
list($key, $value) = each($res);
return $value;
}
function sql_error($query, $values, $result) {
global $ADODB_LASTDB;
trigger_error($ADODB_LASTDB . " error: " . $this->db->ErrorMsg(). " in query:<br/>" . $query . "<br/>", E_USER_WARNING);
// only for debugging.
print_r($values);
//echo "<br/>";
die;
}
// functions to support DB abstraction
function convert_query(&$query) {
global $ADODB_LASTDB;
switch ($ADODB_LASTDB) {
case "oci8":
$query = preg_replace("/`/", "\"", $query);
// convert bind variables - adodb does not do that
$qe = explode("?", $query);
$query = '';
for ($i = 0; $i < sizeof($qe) - 1; $i++) {
$query .= $qe[$i] . ":" . $i;
}
$query .= $qe[$i];
break;
case "postgres7":
case "sybase":
$query = preg_replace("/`/", "\"", $query);
break;
}
}
function convert_sortmode($sort_mode) {
global $ADODB_LASTDB;
switch ($ADODB_LASTDB) {
case "pgsql72":
case "postgres7":
case "oci8":
case "sybase":
// Postgres needs " " around column names
//preg_replace("#([A-Za-z]+)#","\"\$1\"",$sort_mode);
$sort_mode = str_replace("_", "\" ", $sort_mode);
$sort_mode = "\"" . $sort_mode;
break;
case "mysql3":
case "mysql":
default:
$sort_mode = str_replace("_", "` ", $sort_mode);
$sort_mode = "`" . $sort_mode;
break;
}
return $sort_mode;
}
function convert_binary() {
global $ADODB_LASTDB;
switch ($ADODB_LASTDB) {
case "pgsql72":
case "oci8":
case "postgres7":
return;
break;
case "mysql3":
case "mysql":
return "binary";
break;
}
}
function qstr($string, $quoted = null)
{
if (!isset($quoted)) {
$quoted = get_magic_quotes_gpc();
}
return $this->db->qstr($string,$quoted);
}
} //end of class
?>

View File

@ -0,0 +1,81 @@
<?php
//!! Observable
//! An abstract class implementing observable objects
/*!
\abstract
Methods to override: NONE
This class implements the Observer design pattern defining Observable
objects, when a class extends Observable Observers can be attached to
the class listening for some event. When an event is detected in any
method of the derived class the method can call notifyAll($event,$msg)
to notify all the observers listening for event $event.
The Observer objects must extend the Observer class and define the
notify($event,$msg) method.
*/
class Observable {
var $_observers=Array();
function Observable() {
}
/*!
This method can be used to attach an object to the class listening for
some specific event. The object will be notified when the specified
event is triggered by the derived class.
*/
function attach($event, &$obj)
{
if (!is_object($obj)) {
return false;
}
$obj->_observerId = uniqid(rand());
$this->_observers[$event][$obj->_observerId] = &$obj;
}
/*!
Attaches an object to the class listening for any event.
The object will be notified when any event occurs in the derived class.
*/
function attach_all(&$obj)
{
if (!is_object($obj)) {
return false;
}
$obj->_observerId = uniqid(rand());
$this->_observers['all'][$obj->_observerId] = &$obj;
}
/*!
Detaches an observer from the class.
*/
function dettach(&$obj)
{
if (isset($this->_observers[$obj->_observerId])) {
unset($this->_observers[$obj->_observerId]);
}
}
/*!
\protected
Method used to notify objects of an event. This is called in the
methods of the derived class that want to notify some event.
*/
function notify_all($event, $msg)
{
//reset($this->_observers[$event]);
if(isset($this->_observers[$event])) {
foreach ($this->_observers[$event] as $observer) {
$observer->notify($event,$msg);
}
}
if(isset($this->_observers['all'])) {
foreach ($this->_observers['all'] as $observer) {
$observer->notify($event,$msg);
}
}
}
}
?>

View File

@ -0,0 +1,27 @@
<?php
//!! Observer
//! An abstract class implementing observer objects
/*!
\abstract
Methods to override: notify($event, $msg)
This implements the Observer design pattern defining the Observer class.
Observer objects can be "attached" to Observable objects to listen for
a specific event.
Example:
$log = new Logger($logfile); //Logger extends Observer
$foo = new Foo(); //Foo extends Observable
$foo->attach('moo',$log); //Now $log observers 'moo' events in $foo class
// of
$foo->attach_all($log); // Same but all events are listened
*/
class Observer {
///This will be assigned by an observable object when attaching.
var $_observerId='';
function notify($event, $msg) {
// do something...
}
}
?>