diff --git a/phpgwapi/inc/galaxia_workflow/compiler/_shared_pos.php b/phpgwapi/inc/galaxia_workflow/compiler/_shared_pos.php new file mode 100644 index 0000000000..1f90d01d56 --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/compiler/_shared_pos.php @@ -0,0 +1,3 @@ + diff --git a/phpgwapi/inc/galaxia_workflow/compiler/_shared_pre.php b/phpgwapi/inc/galaxia_workflow/compiler/_shared_pre.php new file mode 100644 index 0000000000..04081ca7c1 --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/compiler/_shared_pre.php @@ -0,0 +1,3 @@ + diff --git a/phpgwapi/inc/galaxia_workflow/compiler/activity_pos.php b/phpgwapi/inc/galaxia_workflow/compiler/activity_pos.php new file mode 100644 index 0000000000..7f335b1908 --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/compiler/activity_pos.php @@ -0,0 +1,3 @@ + diff --git a/phpgwapi/inc/galaxia_workflow/compiler/activity_pre.php b/phpgwapi/inc/galaxia_workflow/compiler/activity_pre.php new file mode 100644 index 0000000000..5f9d6f87d6 --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/compiler/activity_pre.php @@ -0,0 +1,20 @@ +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); +} + +?> diff --git a/phpgwapi/inc/galaxia_workflow/compiler/end_pos.php b/phpgwapi/inc/galaxia_workflow/compiler/end_pos.php new file mode 100644 index 0000000000..3d74f3cde9 --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/compiler/end_pos.php @@ -0,0 +1,3 @@ + diff --git a/phpgwapi/inc/galaxia_workflow/compiler/end_pre.php b/phpgwapi/inc/galaxia_workflow/compiler/end_pre.php new file mode 100644 index 0000000000..af2afaf7c4 --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/compiler/end_pre.php @@ -0,0 +1,20 @@ +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); +} + +?> diff --git a/phpgwapi/inc/galaxia_workflow/compiler/join_pos.php b/phpgwapi/inc/galaxia_workflow/compiler/join_pos.php new file mode 100644 index 0000000000..36c6aca604 --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/compiler/join_pos.php @@ -0,0 +1,3 @@ + diff --git a/phpgwapi/inc/galaxia_workflow/compiler/join_pre.php b/phpgwapi/inc/galaxia_workflow/compiler/join_pre.php new file mode 100644 index 0000000000..7936b9825c --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/compiler/join_pre.php @@ -0,0 +1,20 @@ +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); +} + +?> diff --git a/phpgwapi/inc/galaxia_workflow/compiler/split_pos.php b/phpgwapi/inc/galaxia_workflow/compiler/split_pos.php new file mode 100644 index 0000000000..3c77cb39d4 --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/compiler/split_pos.php @@ -0,0 +1,3 @@ + diff --git a/phpgwapi/inc/galaxia_workflow/compiler/split_pre.php b/phpgwapi/inc/galaxia_workflow/compiler/split_pre.php new file mode 100644 index 0000000000..893754c02d --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/compiler/split_pre.php @@ -0,0 +1,20 @@ +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); +} + +?> diff --git a/phpgwapi/inc/galaxia_workflow/compiler/standalone_pos.php b/phpgwapi/inc/galaxia_workflow/compiler/standalone_pos.php new file mode 100644 index 0000000000..8041380a7d --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/compiler/standalone_pos.php @@ -0,0 +1,3 @@ + diff --git a/phpgwapi/inc/galaxia_workflow/compiler/standalone_pre.php b/phpgwapi/inc/galaxia_workflow/compiler/standalone_pre.php new file mode 100644 index 0000000000..69859b9297 --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/compiler/standalone_pre.php @@ -0,0 +1,3 @@ + diff --git a/phpgwapi/inc/galaxia_workflow/compiler/start_pos.php b/phpgwapi/inc/galaxia_workflow/compiler/start_pos.php new file mode 100644 index 0000000000..424ce308ad --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/compiler/start_pos.php @@ -0,0 +1,3 @@ + diff --git a/phpgwapi/inc/galaxia_workflow/compiler/start_pre.php b/phpgwapi/inc/galaxia_workflow/compiler/start_pre.php new file mode 100644 index 0000000000..f76a04a1d5 --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/compiler/start_pre.php @@ -0,0 +1,11 @@ +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 +} + +?> diff --git a/phpgwapi/inc/galaxia_workflow/compiler/switch_pos.php b/phpgwapi/inc/galaxia_workflow/compiler/switch_pos.php new file mode 100644 index 0000000000..da816dc1f7 --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/compiler/switch_pos.php @@ -0,0 +1,3 @@ + diff --git a/phpgwapi/inc/galaxia_workflow/compiler/switch_pre.php b/phpgwapi/inc/galaxia_workflow/compiler/switch_pre.php new file mode 100644 index 0000000000..03292d5b69 --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/compiler/switch_pre.php @@ -0,0 +1,20 @@ +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); +} + +?> diff --git a/phpgwapi/inc/galaxia_workflow/config.egw.inc.php b/phpgwapi/inc/galaxia_workflow/config.egw.inc.php new file mode 100644 index 0000000000..90e6181aa7 --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/config.egw.inc.php @@ -0,0 +1,125 @@ +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&iid=$iid&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); + } +} + +?> diff --git a/phpgwapi/inc/galaxia_workflow/src/API/BaseActivity.php b/phpgwapi/inc/galaxia_workflow/src/API/BaseActivity.php new file mode 100644 index 0000000000..a145e00072 --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/src/API/BaseActivity.php @@ -0,0 +1,218 @@ +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)); + } + +} +?> diff --git a/phpgwapi/inc/galaxia_workflow/src/API/Instance.php b/phpgwapi/inc/galaxia_workflow/src/API/Instance.php new file mode 100644 index 0000000000..e693f666dd --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/src/API/Instance.php @@ -0,0 +1,655 @@ +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;$iactivities);$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;$iactivities);$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;$iactivities);$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;$iactivities);$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;$iactivities);$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;$iactivities);$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;$iactivities);$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; + } + +} +?> diff --git a/phpgwapi/inc/galaxia_workflow/src/API/Process.php b/phpgwapi/inc/galaxia_workflow/src/API/Process.php new file mode 100644 index 0000000000..a0ef8e88fd --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/src/API/Process.php @@ -0,0 +1,76 @@ +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; + } + +} + +?> diff --git a/phpgwapi/inc/galaxia_workflow/src/API/Role.php b/phpgwapi/inc/galaxia_workflow/src/API/Role.php new file mode 100644 index 0000000000..ca21adf8a1 --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/src/API/Role.php @@ -0,0 +1,12 @@ + diff --git a/phpgwapi/inc/galaxia_workflow/src/API/Workitem.php b/phpgwapi/inc/galaxia_workflow/src/API/Workitem.php new file mode 100644 index 0000000000..532931e9db --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/src/API/Workitem.php @@ -0,0 +1,16 @@ + diff --git a/phpgwapi/inc/galaxia_workflow/src/API/activities/Activity.php b/phpgwapi/inc/galaxia_workflow/src/API/activities/Activity.php new file mode 100644 index 0000000000..7b922a28e0 --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/src/API/activities/Activity.php @@ -0,0 +1,14 @@ +setDb($db); + } +} +?> diff --git a/phpgwapi/inc/galaxia_workflow/src/API/activities/End.php b/phpgwapi/inc/galaxia_workflow/src/API/activities/End.php new file mode 100644 index 0000000000..019b5e4bf8 --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/src/API/activities/End.php @@ -0,0 +1,14 @@ +setDb($db); + } +} +?> diff --git a/phpgwapi/inc/galaxia_workflow/src/API/activities/Join.php b/phpgwapi/inc/galaxia_workflow/src/API/activities/Join.php new file mode 100644 index 0000000000..85489521db --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/src/API/activities/Join.php @@ -0,0 +1,14 @@ +setDb($db); + } +} +?> diff --git a/phpgwapi/inc/galaxia_workflow/src/API/activities/Split.php b/phpgwapi/inc/galaxia_workflow/src/API/activities/Split.php new file mode 100644 index 0000000000..b6cd472904 --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/src/API/activities/Split.php @@ -0,0 +1,14 @@ +setDb($db); + } +} +?> diff --git a/phpgwapi/inc/galaxia_workflow/src/API/activities/Standalone.php b/phpgwapi/inc/galaxia_workflow/src/API/activities/Standalone.php new file mode 100644 index 0000000000..030847feaa --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/src/API/activities/Standalone.php @@ -0,0 +1,14 @@ +setDb($db); + } +} +?> diff --git a/phpgwapi/inc/galaxia_workflow/src/API/activities/Start.php b/phpgwapi/inc/galaxia_workflow/src/API/activities/Start.php new file mode 100644 index 0000000000..a501d29f1e --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/src/API/activities/Start.php @@ -0,0 +1,14 @@ +setDb($db); + } +} +?> diff --git a/phpgwapi/inc/galaxia_workflow/src/API/activities/SwitchActivity.php b/phpgwapi/inc/galaxia_workflow/src/API/activities/SwitchActivity.php new file mode 100644 index 0000000000..9218d45535 --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/src/API/activities/SwitchActivity.php @@ -0,0 +1,14 @@ +setDb($db); + } +} +?> diff --git a/phpgwapi/inc/galaxia_workflow/src/GUI/GUI.php b/phpgwapi/inc/galaxia_workflow/src/GUI/GUI.php new file mode 100644 index 0000000000..d2be5116f4 --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/src/GUI/GUI.php @@ -0,0 +1,315 @@ +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)); + } +} +?> diff --git a/phpgwapi/inc/galaxia_workflow/src/Observers/Logger.php b/phpgwapi/inc/galaxia_workflow/src/Observers/Logger.php new file mode 100644 index 0000000000..74ccb55535 --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/src/Observers/Logger.php @@ -0,0 +1,33 @@ +_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); + } +} +?> diff --git a/phpgwapi/inc/galaxia_workflow/src/ProcessManager/ActivityManager.php b/phpgwapi/inc/galaxia_workflow/src/ProcessManager/ActivityManager.php new file mode 100644 index 0000000000..965553089d --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/src/ProcessManager/ActivityManager.php @@ -0,0 +1,842 @@ +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;$iquery($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); + } + +} + + +?> diff --git a/phpgwapi/inc/galaxia_workflow/src/ProcessManager/BaseManager.php b/phpgwapi/inc/galaxia_workflow/src/ProcessManager/BaseManager.php new file mode 100644 index 0000000000..c17d618f5f --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/src/ProcessManager/BaseManager.php @@ -0,0 +1,22 @@ +db = $db; + } + +} //end of class + +?> diff --git a/phpgwapi/inc/galaxia_workflow/src/ProcessManager/GraphViz.php b/phpgwapi/inc/galaxia_workflow/src/ProcessManager/GraphViz.php new file mode 100644 index 0000000000..7a4479a7bc --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/src/ProcessManager/GraphViz.php @@ -0,0 +1,465 @@ + and | +// | Dr. Volker Göbbels . | +// +----------------------------------------------------------------------+ +// | 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 +* Dr. Volker Göbbels +* @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; + } +} +?> diff --git a/phpgwapi/inc/galaxia_workflow/src/ProcessManager/InstanceManager.php b/phpgwapi/inc/galaxia_workflow/src/ProcessManager/InstanceManager.php new file mode 100644 index 0000000000..076a920a97 --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/src/ProcessManager/InstanceManager.php @@ -0,0 +1,86 @@ +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); + } + +} + +?> diff --git a/phpgwapi/inc/galaxia_workflow/src/ProcessManager/ProcessManager.php b/phpgwapi/inc/galaxia_workflow/src/ProcessManager/ProcessManager.php new file mode 100644 index 0000000000..eda8e6eb4c --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/src/ProcessManager/ProcessManager.php @@ -0,0 +1,720 @@ +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) + { + // + $out = ''."\n"; + $proc_info = $this->get_process($pId); + $procname = $proc_info['normalized_name']; + $out.= ' '.htmlspecialchars($proc_info['name']).''."\n"; + $out.= ' '.htmlspecialchars($proc_info['isValid']).''."\n"; + $out.= ' '.htmlspecialchars($proc_info['version']).''."\n"; + $out.= ' '.htmlspecialchars($proc_info['isActive']).''."\n"; + $out.=' '.htmlspecialchars($proc_info['description']).''."\n"; + $out.= ' '.date("d/m/Y [h:i:s]",$proc_info['lastModif']).''."\n"; + $out.= ' '."\n"; + // Now loop over activities + $query = "select * from ".GALAXIA_TABLE_PREFIX."activities where pId=$pId"; + $result = $this->query($query); + $out.=' '."\n"; + $am = new ActivityManager($this->db); + while($res = $result->fetchRow()) { + $name = $res['normalized_name']; + $out.=' '."\n"; + $out.=' '.htmlspecialchars($res['name']).''."\n"; + $out.=' '.htmlspecialchars($res['type']).''."\n"; + $out.=' '.htmlspecialchars($res['description']).''."\n"; + $out.=' '.date("d/m/Y [h:i:s]",$res['lastModif']).''."\n"; + $out.=' '.$res['isInteractive'].''."\n"; + $out.=' '.$res['isAutoRouted'].''."\n"; + $out.=' '."\n"; + + $roles = $am->get_activity_roles($res['activityId']); + foreach($roles as $role) { + $out.=' '.htmlspecialchars($role['name']).''."\n"; + } + $out.=' '."\n"; + $out.=' '; + if($res['isInteractive']=='y') { + $out.=' '; + } + $out.=' '."\n"; + } + $out.=' '."\n"; + $out.=' '."\n"; + $transitions = $am->get_process_transitions($pId); + foreach($transitions as $tran) { + $out.=' '."\n"; + $out.=' '.htmlspecialchars($tran['actFromName']).''."\n"; + $out.=' '.htmlspecialchars($tran['actToName']).''."\n"; + $out.=' '."\n"; + } + $out.=' '."\n"; + $out.= ''."\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;$itree[1]['children']);$i++) { + // Process attributes + $z=$this->tree[1]['children'][$i]; + $name = trim($this->tree[$z]['name']); + if($name=='activities') { + for($j=0;$jtree[$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;$ktree[$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;$ltree[$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
"); + } + } + $aux['roles']=$roles; + $activities[]=$aux; + } + } + } elseif($name=='transitions') { + for($j=0;$jtree[$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;$ktree[$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
"); + $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; + } + +} + + +?> diff --git a/phpgwapi/inc/galaxia_workflow/src/ProcessManager/RoleManager.php b/phpgwapi/inc/galaxia_workflow/src/ProcessManager/RoleManager.php new file mode 100644 index 0000000000..be62b26cbc --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/src/ProcessManager/RoleManager.php @@ -0,0 +1,213 @@ +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; + } +} + +?> diff --git a/phpgwapi/inc/galaxia_workflow/src/ProcessMonitor/ProcessMonitor.php b/phpgwapi/inc/galaxia_workflow/src/ProcessMonitor/ProcessMonitor.php new file mode 100644 index 0000000000..16a8bb3930 --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/src/ProcessMonitor/ProcessMonitor.php @@ -0,0 +1,389 @@ +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; + } + + +} +?> diff --git a/phpgwapi/inc/galaxia_workflow/src/common/Base.php b/phpgwapi/inc/galaxia_workflow/src/common/Base.php new file mode 100644 index 0000000000..5c7da7da6c --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/src/common/Base.php @@ -0,0 +1,130 @@ +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:
" . $query . "
", E_USER_WARNING); + // only for debugging. + print_r($values); + //echo "
"; + 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 + +?> diff --git a/phpgwapi/inc/galaxia_workflow/src/common/Observable.php b/phpgwapi/inc/galaxia_workflow/src/common/Observable.php new file mode 100644 index 0000000000..d2ad99a8f9 --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/src/common/Observable.php @@ -0,0 +1,81 @@ +_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); + } + } + + } + +} +?> \ No newline at end of file diff --git a/phpgwapi/inc/galaxia_workflow/src/common/Observer.php b/phpgwapi/inc/galaxia_workflow/src/common/Observer.php new file mode 100644 index 0000000000..8ac67d7d89 --- /dev/null +++ b/phpgwapi/inc/galaxia_workflow/src/common/Observer.php @@ -0,0 +1,27 @@ +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... + } +} +?>