[ Index ]
 

Code source de eGroupWare 1.2.106-2

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/workflow/inc/engine/src/API/ -> Instance.php (source)

   1  <?php
   2  require_once (GALAXIA_LIBRARY.SEP.'src'.SEP.'common'.SEP.'Base.php');
   3  require_once(GALAXIA_LIBRARY . SEP . 'src' . SEP . 'common' . SEP . 'WfSecurity.php');
   4  require_once(GALAXIA_LIBRARY . SEP . 'src' . SEP . 'ProcessManager' . SEP . 'ActivityManager.php');
   5  
   6  //!! Instance
   7  //! A class representing a process instance.
   8  /*!
   9  This class represents a process instance, it is used when any activity is
  10  executed. The $instance object is created representing the instance of a
  11  process being executed in the activity or even a to-be-created instance
  12  if the activity is a start activity.
  13  */
  14  class Instance extends Base {
  15    //theses are the member of the instance object changed_ vars are internal members
  16    //use to detect conflicts on sync with the database
  17    var $changed = Array('properties' => Array(), 'nextActivity' => Array());
  18    var $properties = Array();
  19    var $owner = '';
  20    var $status = '';
  21    var $started;
  22    var $nextActivity=Array();
  23    var $nextUser;
  24    var $ended;
  25    var $name='';
  26    var $category;
  27    var $priority = 1;
  28    /// Array of assocs(activityId, status, started, ended, user, name, interactivity, autorouting)
  29    var $activities = Array();
  30    var $pId;
  31    var $instanceId = 0;
  32    /// An array of workitem ids, date, duration, activity name, user, activity type and interactivity
  33    var $workitems = Array(); 
  34    //a security object to perform some tests and locks
  35    var $security;
  36    // this is an internal reminder
  37    var $__activity_completed=false;
  38    //indicator, if true we are not synchronised in the memory object with the database, see sync()
  39    var $unsynch=false;
  40    
  41    //! Constructor
  42    function Instance($db) 
  43    {
  44      $this->child_name = 'Instance';
  45      parent::Base($db);
  46    }
  47  
  48    /*!
  49    * Method used to load an instance data from the database.
  50    * This function will load/initialize members of the instance object from the database
  51    * it will populate all members and will by default populate the related activities array
  52    * and the workitems (history) array.
  53    * @param $instanceId
  54    * @param $load_activities true by default, do we need to reload activities from the database?
  55    * @param $load_workitems true by default, do we need to reload workitems from the database?
  56    */
  57    function getInstance($instanceId, $load_activities=true, $load_workitems=true) 
  58    {
  59      if (!($instanceId)) return true; //start activities for example - pseudo instances
  60      // Get the instance data
  61      $query = "select * from `".GALAXIA_TABLE_PREFIX."instances` where `wf_instance_id`=?";
  62      $result = $this->query($query,array((int)$instanceId));
  63      if( empty($result) || (!$result->numRows())) return false;
  64      $res = $result->fetchRow();
  65      
  66      //Populate 
  67      $this->properties = unserialize(base64_decode($res['wf_properties']));
  68      $this->status = $res['wf_status'];
  69      $this->pId = $res['wf_p_id'];
  70      $this->instanceId = $res['wf_instance_id'];
  71      $this->priority = $res['wf_priority'];
  72      $this->owner = $res['wf_owner'];
  73      $this->started = $res['wf_started'];
  74      $this->ended = $res['wf_ended'];
  75      $this->nextActivity = unserialize(base64_decode($res['wf_next_activity']));
  76      $this->nextUser = $res['wf_next_user'];
  77      $this->name = $res['wf_name'];
  78      $this->category = $res['wf_category'];
  79  
  80      // Get the activities where the instance is (nothing for start activities)
  81      if ($load_activities)
  82      {
  83        $this->_populate_activities($instanceId);
  84  
  85      }
  86      
  87      // Get the workitems where the instance is
  88      if ($load_workitems)
  89      {
  90        $query = "select wf_item_id, wf_order_id, gw.wf_instance_id, gw.wf_activity_id, wf_started, wf_ended, gw.wf_user,
  91                ga.wf_name, ga.wf_type, ga.wf_is_interactive
  92                from ".GALAXIA_TABLE_PREFIX."workitems gw
  93                INNER JOIN ".GALAXIA_TABLE_PREFIX."activities ga ON ga.wf_activity_id = gw.wf_activity_id
  94                where wf_instance_id=? order by wf_order_id ASC";
  95        $result = $this->query($query,array((int)$instanceId));
  96        if (!(empty($result)))
  97        {
  98          while($res = $result->fetchRow()) 
  99          {
 100            $this->workitems[]=$res;
 101          }
 102        }
 103        return true;
 104      }
 105      
 106    }
 107    
 108    /*!
 109    * @private
 110    * Function used to load all activities related to the insance given in parameter in the activities array
 111    * @param $instanceId is the instanceId
 112    */
 113    function _populate_activities($instanceId)
 114    {
 115      $this->activities=Array();
 116      $query = "select gia.wf_activity_id, gia.wf_instance_id, wf_started, wf_ended, wf_started, wf_user, wf_status,
 117              ga.wf_is_autorouted, ga.wf_is_interactive, ga.wf_name, ga.wf_type
 118              from ".GALAXIA_TABLE_PREFIX."instance_activities gia
 119              INNER JOIN ".GALAXIA_TABLE_PREFIX."activities ga ON ga.wf_activity_id = gia.wf_activity_id
 120              where wf_instance_id=?";
 121      $result = $this->query($query,array((int)$instanceId));
 122      if (!(empty($result)))
 123      {
 124        while($res = $result->fetchRow())
 125        {
 126          $this->activities[] = $res;
 127        }
 128      }
 129    }
 130  
 131    /*!
 132    * @private
 133    */
 134    function _synchronize_member(&$changed,&$init,&$actual,$name,$fieldname,&$namearray,&$vararray)
 135    {
 136      //if we work with arrays then it's more complex
 137      //echo "<br>$name is_array?".(is_array($changed)); _debug_array($changed);
 138      if (!(is_array($changed)))
 139      {
 140        if (isset($changed))
 141        {
 142          //detect unsynchro
 143          if (!($actual==$init))
 144          {
 145            $this->error[] = tra('Instance: unable to modify %1, someone has changed it before us', $name);
 146          }
 147          else
 148          {
 149            $namearray[] = $fieldname;
 150            $vararray[] = $changed;
 151            $actual = $changed;
 152          }
 153      //seems to be not working
 154          unset ($changed);
 155        }
 156      }
 157      else //we are working with arrays (properties for example)
 158      {
 159        $modif_done = false;
 160        foreach ($changed as $key => $value)
 161        {
 162          //detect unsynchro
 163          if (!($actual[$key]==$init[$key]))
 164          {
 165            $this->error[] = tra('Instance: unable to modify %1 [%2], someone has changed it before us', $name, $key);
 166          }
 167          else
 168          {
 169            $actual[$key] = $value;
 170            $modif_done = true;
 171          }
 172        }
 173        if ($modif_done) //at least one modif
 174        {
 175          $namearray[] = $fieldname;
 176          //no more serialize, done by the core security_cleanup
 177          $vararray[] = $actual; //serialize($actual);
 178        }   
 179        $changed=Array();
 180      }
 181    }
 182    
 183    /*!
 184    * @public
 185    * Synchronize the instance object with the database. All change smade will be recorded except
 186    * conflicting ones (changes made on members or properties that has been changed by another source
 187    * --could be another 'instance' of this instance or an admin form-- since the last call of sync() )
 188    * the unsynch private member is used to test if more heavy tests should be done or not
 189    * pseudo instances (start, standalone) are not synchronised since there is no record on database
 190    */
 191    function sync()
 192    {
 193      if ( (!($this->instanceId)) || (!($this->unsynch)) )
 194      {
 195        //echo "<br>nothing to do ".$this->unsynch;
 196        return true;
 197      }
 198      //echo "<br> synch!";_debug_array($this->changed);
 199      //do it in a transaction, can have several activities running
 200      $this->db->StartTrans();
 201      //we need to make a row lock now,
 202      $where = 'wf_instance_id='.(int)$this->instanceId;
 203      if (!($this->db->RowLock(GALAXIA_TABLE_PREFIX.'instances', $where)))
 204      {
 205        $this->error[] = 'sync: '.tra('failed to obtain lock on %1 table', 'instances');
 206        $this->db->FailTrans();
 207      }
 208      else
 209      {
 210        //wf_p_id and wf_instance_id are set in creation only.
 211        //we remember initial values
 212        $init_properties = $this->properties;
 213        $init_status = $this->status;
 214        $init_priority = $this->priority;
 215        $init_owner = $this->owner;
 216        $init_started = $this->started;
 217        $init_ended = $this->ended;
 218        $init_nextUser = $this->nextUser;
 219        $init_nextActivity = $this->nextActivity;
 220        $init_name = $this->name;
 221        $init_category = $this->category;
 222        // we re-read instance members to detect conflicts, changes made while we were unsynchronised
 223          // TODO: there is instanceID and instance_id, all around that's bad!!!
 224        $this->getInstance($this->instanceId, false, false);
 225        // Now for each modified field we'll change the database value if nobody has changed
 226        // the database value before us
 227        $bindvars = Array();
 228        $querysets = Array();
 229        $queryset = '';
 230        $this->_synchronize_member($this->changed['status'],$init_status,$this->status,tra('status'),'wf_status',$querysets,$bindvars);
 231      unset ($this->changed['status']);
 232        $this->_synchronize_member($this->changed['priority'],$init_priority,$this->priority,tra('priority'),'wf_priority',$querysets,$bindvars);
 233      unset ($this->changed['priority']);
 234        $this->_synchronize_member($this->changed['owner'],$init_owner,$this->owner,tra('owner'),'wf_owner',$querysets,$bindvars);
 235      unset ($this->changed['owner']);
 236        $this->_synchronize_member($this->changed['started'],$init_started,$this->started,tra('started'),'wf_started',$querysets,$bindvars);
 237      unset ($this->changed['started']);
 238        $this->_synchronize_member($this->changed['ended'],$init_ended,$this->ended,tra('ended'),'wf_ended',$querysets,$bindvars);
 239      unset ($this->changed['ended']);
 240        $this->_synchronize_member($this->changed['name'],$init_name,$this->name,tra('name'),'wf_name',$querysets,$bindvars);
 241      unset ($this->changed['name']);
 242        $this->_synchronize_member($this->changed['category'],$init_category,$this->category,tra('category'),'wf_category',$querysets,$bindvars);
 243        $this->_synchronize_member($this->changed['properties'],$init_properties,$this->properties,tra('property'),'wf_properties',$querysets,$bindvars);
 244        $this->_synchronize_member($this->changed['nextActivity'],$init_nextActivity,$this->nextActivity,tra('next activity'),'wf_next_activity',$querysets,$bindvars);
 245        $this->_synchronize_member($this->changed['nextUser'],$init_nextUser,$this->nextUser,tra('next user'),'wf_next_user',$querysets,$bindvars);
 246      unset ($this->changed['nextUser']);
 247        if (!(empty($querysets)))
 248        {
 249          $queryset = implode(' = ?,', $querysets). ' = ?';
 250          $query = 'update '.GALAXIA_TABLE_PREFIX.'instances set '.$queryset
 251                .' where wf_instance_id=?';
 252          $bindvars[] = $this->instanceId;
 253          //echo "<br> query $query"; _debug_array($bindvars);
 254          $this->query($query,$bindvars);
 255        }
 256      }
 257      if (!($this->db->CompleteTrans()))
 258      {
 259        $this->error[] = tra('failed to synchronize instance data with the database');
 260        return false;
 261      }
 262  
 263      //we are not unsynchronized anymore.
 264      $this->unsynch = false;
 265      return true;
 266    }
 267    
 268    /*! 
 269    * Sets the next activity to be executed, if the current activity is
 270    * a switch activity the complete() method will use the activity setted
 271    * in this method as the next activity for the instance. 
 272    * The object records an array of transitions, as the instance can be splitted in several 
 273    * running activities, transition from the current activity to the given activity will
 274    * be recorded and all previous recorded transitions starting from the current activity
 275    * will be deleted.
 276    * @param $activityId is the running activity Id 
 277    * @param $actname Warning this method receives an activity name as argument. (Not an Id)
 278    * @return true or false
 279    */
 280    function setNextActivity($activityId, $actname) 
 281    {
 282      $pId = $this->pId;
 283      $actname=trim($actname);
 284      $aid = $this->getOne('select wf_activity_id from '.GALAXIA_TABLE_PREFIX.'activities where wf_p_id=? and wf_name=?',array($pId,$actname));
 285      if (!($aid))
 286      {
 287        $this->error[] = tra('setting next activity to an unexisting activity');
 288        return false;
 289      }
 290      $this->changed['nextActivity'][$activityId]=$aid;
 291      $this->unsynch = true;
 292      return true;
 293    }
 294  
 295    /*!
 296    This method can be used to set the user that must perform the next 
 297    activity of the process. this effectively "assigns" the instance to
 298    some user.
 299    */
 300    function setNextUser($user) {
 301      // TODO: check if $user<>changed['nextUser'] before unsynching
 302      $this->changed['nextUser'] = $user;
 303      $this->unsynch = true;
 304      return true;
 305    }
 306  
 307    /*!
 308    This method can be used to get the user that must perform the next 
 309    activity of the process. This can be empty if no setNextUser was done before.
 310    It wont return the default user but only the user which was assigned by a setNextUser.
 311    */
 312    function getNextUser() 
 313    {
 314      if (!(isset($this->changed['nextUser'])))
 315      {
 316        return $this->nextUser;
 317      }
 318      else
 319      {
 320        return $this->changed['nextUser'];
 321      }
 322    }
 323   
 324    /*!
 325    * @private
 326    * Creates a new instance.
 327    * This method is called in start activities when the activity is completed
 328    * to create a new instance representing the started process.
 329    * @param $activityId is the start activity id
 330    * @param $user is the current user id
 331    * @return true if all things goes well
 332    */
 333    function _createNewInstance($activityId,$user) {
 334      // Creates a new instance setting up started, ended, user, status and owner
 335      $pid = $this->getOne('select wf_p_id from '.GALAXIA_TABLE_PREFIX.'activities where wf_activity_id=?',array((int)$activityId));
 336      $this->pId = $pid;
 337      $this->setStatus('active');
 338      $this->setNextUser('');
 339      //we pass extra args to started and owner to ignore synchro as we'll insert them just here
 340      $now = date("U");
 341      $this->setStarted($now, true);
 342      $this->setOwner($user, true);
 343  
 344      //we insert started and owner here and we used them to detect instanceId, this could disturb synchro
 345      $query = 'insert into '.GALAXIA_TABLE_PREFIX.'instances
 346        (wf_started,wf_ended,wf_p_id,wf_owner,wf_properties) 
 347        values(?,?,?,?,?)';
 348      $this->query($query,array($now,0,$pid,$user,$this->security_cleanup(Array(),false)));
 349      $this->instanceId = $this->getOne('select max(wf_instance_id) from '.GALAXIA_TABLE_PREFIX.'instances 
 350                        where wf_started=? and wf_owner=?',array((int)$now,$user));
 351      $iid=$this->instanceId;
 352      
 353      // Then add in instance_activities an entry for the
 354      // activity the user and status running and started now
 355      $query = 'insert into '.GALAXIA_TABLE_PREFIX.'instance_activities (wf_instance_id,wf_activity_id,wf_user,
 356              wf_started,wf_status) values(?,?,?,?,?)';
 357      $this->query($query,array((int)$iid,(int)$activityId,$user,(int)$now,'running'));
 358      
 359      //update database with other datas stored in the object
 360          //echo "<br/> syncing  in _createNewInstance";
 361      return $this->sync();
 362    }
 363    
 364    /*!
 365    Sets the name of this instance.
 366    */
 367    function setName($value) 
 368    {
 369      $this->changed['name'] = substr($value,0,120);
 370      $this->unsynch = true;
 371      return true;
 372    }
 373  
 374    /*!
 375    Get the name of this instance.
 376    */
 377    function getName() 
 378    {
 379      if (!(isset($this->changed['name'])))
 380      {
 381        return $this->name;
 382      }
 383      else
 384      {
 385        return $this->changed['name'];
 386      }
 387    }
 388  
 389    /*!
 390    * Sets the category of this instance.
 391    */
 392    function setCategory($value) 
 393    {
 394      $this->changed['category'] = $value;
 395      $this->unsynch = true;
 396      return true;
 397    }
 398  
 399    /*!
 400    * Get the category of this instance.
 401    */
 402    function getCategory() 
 403    {
 404      if (!(isset($this->changed['category'])))
 405      {
 406        return $this->category;
 407      }
 408      else
 409      {
 410        return $this->changed['category'];
 411      }
 412    }
 413  
 414    /*!
 415    * @private
 416    * Normalizes a property name
 417    * @param $name is the name you want to normalize
 418    * @return the property name
 419    */
 420    function _normalize_name($name)
 421    {
 422      $name = trim($name);
 423      $name = str_replace(" ","_",$name);
 424      $name = preg_replace("/[^0-9A-Za-z\_]/",'',$name);
 425      return $name;
 426    }
 427  
 428    /*! 
 429    * Sets a property in this instance. This method is used in activities to
 430    * set instance properties.
 431    * all property names are normalized for security reasons and to avoid localisation
 432    * problems (A->z, digits and _ for spaces). If you have several set to call look
 433    * at the setProperties function. Each call to this function has an impact on database
 434    * @param $name is the property name (it will be normalized)
 435    * @value is the value you want for this property
 436    * @return true if it was ok
 437    */
 438    function set($name,$value) 
 439    {
 440      $name = $this->_normalize_name($name);
 441      $this->changed['properties'][$name] = $this->security_cleanup($value);
 442      $this->unsynch = true;
 443      return true;
 444    }
 445    
 446    /*! 
 447    * Sets several properties in this instance. This method is used in activities to
 448    * set instance properties. Use this method if you have several properties to set
 449    * as it will avoid to re-call the SQL engine for each property.
 450    * all property names are normalized for security reasons and to avoid localisation
 451    * problems (A->z, digits and _ for spaces). 
 452    * @param $properties_array is an associative array containing for each record the
 453    * property name as the key and the property value as the value.
 454    * @return true if it was ok
 455    */
 456    function setProperties($properties_array) 
 457    {
 458      $backup_values = $this->properties;
 459      foreach ($properties_array as $key => $value)
 460      {
 461        $name = $this->_normalize_name($key);
 462        $this->changed['properties'][$name] = $this->security_cleanup($value);
 463      }
 464      $this->unsynch = true;
 465      return true;
 466    }
 467    
 468  
 469    /*! 
 470    * Gets the value of an instance property.
 471    * @param $name is the name of the property
 472    * @return false if the property was not found, in this case an error message is stored in
 473    * the instance object
 474    */
 475    function get($name) 
 476    {
 477      $name = $this->_normalize_name($name);
 478      if(isset($this->changed['properties'][$name])) 
 479      {
 480        return $this->changed['properties'][$name];
 481      }
 482      elseif(isset($this->properties[$name])) 
 483      {
 484        return $this->properties[$name];
 485      } 
 486      else 
 487      {
 488        $this->error[] = tra('property %1 not found', $name);
 489        return false;
 490      }
 491    }
 492    
 493    /*! 
 494    Returns an array of assocs describing the activities where the instance
 495    is present, can be more than one activity if the instance was "splitted"
 496    */
 497    function getActivities() {
 498      return $this->activities;
 499    }
 500    
 501    /*! 
 502    Gets the instance status can be
 503    'completed', 'active', 'aborted' or 'exception'
 504    */
 505    function getStatus() {
 506      if (!(isset($this->changed['status'])))
 507      {
 508        return $this->status;
 509      }
 510      else
 511      {
 512        return $this->changed['status'];
 513      }
 514    }
 515    
 516    /*! 
 517    * Sets the instance status
 518    * @param $status is the status you want, it can be:
 519    * 'completed', 'active', 'aborted' or 'exception'
 520    * @return true or false
 521    */
 522    function setStatus($status) 
 523    {
 524      if (!(($status=='completed') || ($status=='active') || ($status=='aborted') || ($status=='exception')))
 525      {
 526        $this->error[] = tra('unknown status');
 527        return false;
 528      }
 529      $this->changed['status'] = $status; 
 530      $this->unsynch = true;
 531      return true;
 532    }
 533    
 534    /*!
 535    Gets the instance priority, it's an integer
 536    */
 537    function getPriority()
 538    {
 539      if (!(isset($this->changed['priority'])))
 540      {
 541        return $this->priority;
 542      }
 543      else
 544      {
 545        return $this->changed['priority'];
 546      }
 547    } 
 548  
 549    /*!
 550    Sets the instance priority , the value should be an integer
 551    */
 552    function setPriority($priority)
 553    {
 554      $mypriority = (int)$priority;
 555      $this->changed['priority'] = $mypriority;
 556      $this->unsynch = true;
 557      return true;
 558    }
 559     
 560    /*!
 561    Returns the instanceId
 562    */
 563    function getInstanceId() 
 564    {
 565      return $this->instanceId;
 566    }
 567    
 568    /*! 
 569    Returns the processId for this instance
 570    */
 571    function getProcessId() 
 572    {
 573      return $this->pId;
 574    }
 575    
 576    /*! 
 577    Returns the user that created the instance
 578    */
 579    function getOwner() 
 580    {
 581      if (!(isset($this->changed['owner'])))
 582      {
 583        return $this->owner;
 584      }
 585      else
 586      {
 587        return $this->changed['owner'];
 588      }
 589    }
 590    
 591    /*! 
 592    * Sets the instance creator user. 
 593    * @param $user is the new owner id, musn't be false, 0 or empty
 594    * @param $ignore_unsynch is false by default, used to set owner with a user already set in database, do not use it unless 
 595    * you know very well what you're doing
 596    * @return true if the change was done
 597    */
 598    function setOwner($user,$ignore_unsynch=false) 
 599    {
 600      if (empty($user))
 601      { 
 602          return false;
 603      }
 604      if ($ignore_unsynch) 
 605      {
 606          $this->owner=$user;
 607      }
 608      else
 609      {    
 610          $this->changed['owner'] = $user;
 611          $this->unsynch = true;
 612      }
 613      return true;
 614    }
 615    
 616    /*!
 617    * Sets the user that must execute the activity indicated by the activityId.
 618    * Note that the instance MUST be present in the activity to set the user,
 619    * you can't program who will execute an activity.
 620    * If the user is empty then the activity user is setted to *, allowing any
 621    * authorised user to take the token later
 622    * 
 623    * concurrent access to this function is normally handled by WfRuntime and WfSecurity
 624    * theses objects are the only ones which should call this function. WfRuntime is handling the
 625    * current transaction and WfSecurity is Locking the instance and instance_activities table on
 626    * a 'run' action which is the action leading to this setActivityUser call (could be a release 
 627    * as well on auto-release)
 628    * @param $activityId is the activity Id
 629    * @param $theuser is the user id or '*' (or 0, '' or null which will be set to '*')
 630    * @return false if something was wrong
 631    */
 632    function setActivityUser($activityId,$theuser) {
 633      if(empty($theuser)) $theuser='*';
 634      $found = false;
 635      for($i=0;$i<count($this->activities);$i++) {
 636        if($this->activities[$i]['wf_activity_id']==$activityId) {
 637          // here we are in the good activity
 638          $found = true;
 639  
 640          // prepare queries
 641          $where = ' where wf_activity_id=? and wf_instance_id=?';
 642          $bindvars = array((int)$activityId,(int)$this->instanceId);
 643          if(!($theuser=='*')) 
 644          {
 645            $where .= ' and (wf_user=? or wf_user=?)';
 646            $bindvars[]= $theuser;
 647            $bindvars[]= '*';
 648          }
 649          
 650          // update the user
 651          $query = 'update '.GALAXIA_TABLE_PREFIX.'instance_activities set wf_user=?';
 652          $query .= $where;
 653          $bindvars_update = array_merge(array($theuser),$bindvars);
 654          $this->query($query,$bindvars_update);
 655          $this->activities[$i]['wf_user']=$theuser;
 656          return true;
 657        }
 658      }
 659      // if we didn't find the activity it will be false
 660      return $found;
 661    }
 662  
 663    /*!
 664    Returns the user that must execute or is already executing an activity
 665    wherethis instance is present.
 666    */  
 667    function getActivityUser($activityId) {
 668      for($i=0;$i<count($this->activities);$i++) {
 669        if($this->activities[$i]['wf_activity_id']==$activityId) {
 670          return $this->activities[$i]['wf_user'];
 671        }
 672      }  
 673      return false;
 674    }
 675  
 676    /*!
 677    * Sets the status of the instance in some activity
 678    * @param $activityId is the activity id
 679    * @param $status is the new status, it can be 'running' or 'completed'
 680    * @return false if no activity was found for the instance
 681    */  
 682    function setActivityStatus($activityId,$status) 
 683    {
 684      if (!(($status=='running') || ($status=='completed')))
 685      {
 686        $this->error[] = tra('unknown status');
 687        return false;
 688      }
 689      for($i=0;$i<count($this->activities);$i++) 
 690      {
 691        if($this->activities[$i]['wf_activity_id']==$activityId) 
 692        {
 693          $query = 'update '.GALAXIA_TABLE_PREFIX.'instance_activities set wf_status=? where wf_activity_id=? and wf_instance_id=?';
 694          $this->query($query,array($status,(int)$activityId,(int)$this->instanceId));
 695          return true;
 696        }
 697      }
 698      $this->error[] = tra('new status not set, no corresponding activity was found.'); 
 699      return false;
 700    }
 701    
 702    
 703    /*!
 704    Gets the status of the instance in some activity, can be
 705    'running' or 'completed'
 706    */
 707    function getActivityStatus($activityId) {
 708      for($i=0;$i<count($this->activities);$i++) {
 709        if($this->activities[$i]['wf_activity_id']==$activityId) {
 710          return $this->activities[$i]['wf_status'];
 711        }
 712      }
 713      $this->error[] = tra('activity status not avaible, no corresponding activity was found.');
 714      return false;
 715    }
 716    
 717    /*!
 718    Resets the start time of the activity indicated to the current time.
 719    */
 720    function setActivityStarted($activityId) {
 721      $now = date("U");
 722      for($i=0;$i<count($this->activities);$i++) {
 723        if($this->activities[$i]['wf_activity_id']==$activityId) {
 724          $this->activities[$i]['wf_started']=$now;
 725          $query = "update `".GALAXIA_TABLE_PREFIX."instance_activities` set `wf_started`=? where `wf_activity_id`=? and `wf_instance_id`=?";
 726          $this->query($query,array($now,(int)$activityId,(int)$this->instanceId));
 727          return true;
 728        }
 729      }
 730      $this->error[] = tra('activity start not set, no corresponding activity was found.');
 731      return false;
 732    }
 733    
 734    /*!
 735    Gets the Unix timstamp of the starting time for the given activity.
 736    */
 737    function getActivityStarted($activityId) {
 738      for($i=0;$i<count($this->activities);$i++) {
 739        if($this->activities[$i]['wf_activity_id']==$activityId) {
 740          return $this->activities[$i]['wf_started'];
 741        }
 742      }
 743      $this->error[] = tra('activity start not avaible, no corresponding activity was found.');
 744      return false;
 745    }
 746    
 747    /*!
 748    * @private
 749    * Gets an activity from the list of activities of the instance
 750    * the result is an array describing the instance
 751    * @param $activityId is the activity id
 752    * @returns the activity id or false if the activity was not found
 753    */
 754    function _get_instance_activity($activityId) 
 755    {
 756      for($i=0;$i<count($this->activities);$i++) {
 757        if($this->activities[$i]['wf_activity_id']==$activityId) {
 758          return $this->activities[$i];
 759        }
 760      }
 761      $this->error[] = tra('no corresponding activity was found.');
 762      return false;
 763    }
 764  
 765    /*!
 766    * Sets the time where the instance was started.
 767    * @param $time is the started time
 768    * @param $ignore_unsynch is false by default, used to set started with a time already set in database, do not use it unless 
 769    * you know very well what you're doing
 770    * @returns true if everything is well done
 771    */
 772    function setStarted($time,$ignore_unsynch=false) 
 773    {
 774      if ($ignore_unsynch) 
 775      {
 776          $this->started=$time;
 777      }
 778      else
 779      {
 780          $this->changed['started'] = $time;
 781          $this->unsynch = true;
 782      }
 783      return true;
 784    }
 785    
 786    /*!
 787    Gets the time where the instance was started (Unix timestamp)
 788    */
 789    function getStarted() 
 790    {
 791      if (!(isset($this->changed['started'])))
 792      {
 793        return $this->started;
 794      }
 795      else
 796      {
 797        return $this->changed['started'];
 798      }
 799    }
 800    
 801    /*!
 802    Sets the end time of the instance (when the process was completed)
 803    */
 804    function setEnded($time) 
 805    {
 806      $this->changed['ended']=$time;
 807      $this->unsynch = true;
 808      return true;
 809    }
 810    
 811    /*!
 812    Gets the end time of the instance (when the process was completed)
 813    */
 814    function getEnded() 
 815    {
 816      if (!(isset($this->changed['ended'])))
 817      {
 818        return $this->ended;
 819      }
 820      else
 821      {
 822        return $this->changed['ended'];
 823      }
 824    }
 825    
 826    /*!
 827    * @private
 828    * This set to true or false the 'Activity Completed' status which will
 829    * be important to know if the user code has completed the current activity
 830    * @param $bool is true by default, it will be the next status of the 'Activity Completed' indicator
 831    */
 832    function setActivityCompleted($bool)
 833    {
 834      $this->__activity_completed = $bool;
 835    }
 836    
 837    /*!
 838    * @public
 839    * Gets the 'Activity Completed' status
 840    */
 841    function getActivityCompleted()
 842    {
 843      return $this->__activity_completed;
 844    }
 845   
 846    /*
 847    * @public
 848    * This function can be called by the instance object himself (for automatic activities)
 849    * or by the WfRuntime object. In interactive activities code users use complete() --without args-- 
 850    * which refer to the WfRuntime->complete() function which call this one. 
 851    * In non-interactive activities a call to a complete() will generate errors because the engine
 852    * does it his own way as I said first.
 853    * Particularity of this Complete is that it is Transactional, i.e. it it done completely
 854    * or not and row locks are ensured.
 855    * @param $activityId is the activity that is being completed
 856    * @param $addworkitem indicates if a workitem should be added for the completed
 857    * activity (true by default).
 858    * @return true or false, if false it means the complete was not done for some internal reason
 859    * consult $instance->get_error() for more informations
 860    */
 861    function complete($activityId,$addworkitem=true)
 862    {
 863      //ensure it's false at first
 864      $this->setActivityCompleted(false);
 865  
 866      //The complete() is in a transaction, it will be completly done or not at all
 867      $this->db->StartTrans();
 868      
 869      //lock rows and ensure access is granted
 870      if (!(isset($this->security))) $this->security =& new WfSecurity($this->db); 
 871      if (!($this->security->checkUserAction($activityId,$this->instanceId,'complete')))
 872      {
 873        $this->error[] = tra('you were not allowed to complete the activity');
 874        $this->db->FailTrans();
 875      }
 876      else
 877      {
 878        if (!($this->_internalComplete($activityId,$addworkitem)))
 879        {
 880          $this->error[] = tra('The activity was not completed');
 881          $this->db->FailTrans();
 882        }
 883      }
 884      //we mark completion with result of the transaction wich will be false if any error occurs
 885      //this is the end of the transaction
 886      $this->setActivityCompleted($this->db->CompleteTrans());
 887  
 888      //we return the completion state.
 889      return $this->getActivityCompleted();
 890    }
 891  
 892    /*!
 893    * @private
 894    * YOU MUST NOT CALL _internalComplete() directly, use Complete() instead
 895    * @param $activityId is the activity that is being completed
 896    * @param $addworkitem indicates if a workitem should be added for the completed
 897    * activity (true by default).
 898    * @return true or false, if false it means the complete was not done for some internal reason
 899    * consult $instance->get_error() for more informations
 900    */
 901    function _internalComplete($activityId,$addworkitem=true) {
 902      global $user;
 903  
 904      if(empty($user)) 
 905      {
 906        $theuser='*';
 907      } 
 908      else 
 909      {
 910        $theuser=$user;
 911      }
 912  
 913      if(!($activityId)) 
 914      {
 915        $this->error[] = tra('it was impossible to complete, no activity was given.');
 916        return false;
 917      }  
 918      
 919      $now = date("U");
 920      
 921      // If we are completing a start activity then the instance must 
 922      // be created first!
 923      $type = $this->getOne('select wf_type from '.GALAXIA_TABLE_PREFIX.'activities where wf_activity_id=?',array((int)$activityId));
 924      if($type=='start') 
 925      {
 926        if (!($this->_createNewInstance((int)$activityId,$theuser)))
 927        {
 928          return false;
 929        }
 930      }
 931      else
 932      {  
 933        // Now set ended
 934        $query = 'update '.GALAXIA_TABLE_PREFIX.'instance_activities set wf_ended=? where wf_activity_id=? and wf_instance_id=?';
 935        $this->query($query,array((int)$now,(int)$activityId,(int)$this->instanceId));
 936      }
 937      
 938      //Set the status for the instance-activity to completed
 939      //except for start activities
 940      if (!($type=='start'))
 941      {
 942        if (!($this->setActivityStatus($activityId,'completed')))
 943        {
 944          return false;
 945        }
 946      }
 947      
 948      //If this and end actt then terminate the instance
 949      if($type=='end') 
 950      {
 951        if (!($this->terminate($now)))
 952        {
 953          return false;
 954        }
 955      }
 956  
 957      //now we synchronise instance with the database
 958          //echo "<br/> syncing  in _internalComplete";
 959      if (!($this->sync())) return false;
 960      
 961      //Add a workitem to the instance 
 962      if ($addworkitem)
 963      {
 964        return $this->addworkitem($type,$now, $activityId);
 965      }
 966      else
 967      {
 968        return true;
 969      }
 970    }
 971    
 972    /*!
 973    * @private
 974    * This function will add a workitem in the workitems table. The instance MUST be synchronised before
 975    * calling this function.
 976    * @param $activity_type is the activity type, needed because internals are different for start activities
 977    * @param $ended is the ending time
 978    * @param $activityId is the finishing activity id
 979    */
 980    function addworkitem($activity_type, $ended, $activityId)
 981    {
 982      $iid = $this->instanceId;
 983      $max = $this->getOne('select max(wf_order_id) from '.GALAXIA_TABLE_PREFIX.'workitems where wf_instance_id=?',array((int)$iid));
 984      if(!$max) 
 985      {
 986          $max=1;
 987      }
 988      else 
 989      {
 990          $max++;
 991      }
 992      if($activity_type=='start')
 993      {
 994        //Then this is a start activity ending
 995        $started = $this->getStarted();
 996        //at this time owner is the creator
 997        $putuser = $this->getOwner();
 998      }
 999      else
1000      {
1001        $act = $this->_get_instance_activity($activityId);
1002        if(!$act) 
1003        {
1004          //this will abort the function
1005          $this->error[] = tra('failed to create workitem');
1006          return false;
1007        }
1008        else 
1009        {
1010          $started = $act['wf_started'];
1011          $putuser = $act['wf_user'];
1012        }
1013      }
1014      //no more serialize, done by the core security_cleanup
1015      $properties = $this->security_cleanup($this->properties, false); //serialize($this->properties);
1016      $query='insert into '.GALAXIA_TABLE_PREFIX.'workitems
1017          (wf_instance_id,wf_order_id,wf_activity_id,wf_started,wf_ended,wf_properties,wf_user) values(?,?,?,?,?,?,?)';    
1018      $this->query($query,array((int)$iid,(int)$max,(int)$activityId,(int)$started,(int)$ended,$properties,$putuser));
1019      return true;
1020    }
1021    
1022    //! Send autorouted activities to the next one(s). Private engine function
1023    /*
1024    * The arguments are explained just in case.
1025    * @param $activityId is the activity that is being completed, when this is not
1026    * passed the engine takes it from the $_REQUEST array,all activities
1027    * are executed passing the activityId in the URI.
1028    * @param $force indicates that the instance must be routed no matter if the
1029    * activity is auto-routing or not. This is used when "sending" an
1030    * instance from a non-auto-routed activity to the next activity.
1031    * @private
1032    * YOU MUST NOT CALL sendAutorouted() for non-interactive activities since
1033    * the engine does automatically complete and send automatic activities after
1034    * executing them.
1035    * This function is in fact a Private function runned by the engine. You should
1036    * never use it without knowing very very well what you're doing.
1037    * @return false or an array with ['transition']['failure'] set in case of any problem, 
1038    * true if nothing was done and an array if something done, like walk on transition 
1039    * and execution of an activity (see sendTo comments) or if this activity was a split 
1040    * activity (in this case the array contains a row for each following activity)
1041    */
1042    function sendAutorouted($activityId,$force=false)
1043    {
1044      $returned_value = Array();
1045      $type = $this->getOne("select `wf_type` from `".GALAXIA_TABLE_PREFIX."activities` where `wf_activity_id`=?",array((int)$activityId));    
1046      //on a end activity we have nothing to do
1047      if ($type == 'end')
1048      {
1049        return true;
1050      }
1051      //If the activity ending is not autorouted then we have nothing to do
1052      if (!(($force) || ($this->getOne("select `wf_is_autorouted` from `".GALAXIA_TABLE_PREFIX."activities` where `wf_activity_id`=?",array($activityId)) == 'y')))
1053      {
1054        $returned_value['transition']['status'] = 'not autorouted';
1055        return $returned_value;
1056      }
1057      //If the activity ending is autorouted then send to the activity
1058      // Now determine where to send the instance
1059      $query = "select `wf_act_to_id` from `".GALAXIA_TABLE_PREFIX."transitions` where `wf_act_from_id`=?";
1060      $result = $this->query($query,array((int)$activityId));
1061      $candidates = Array();
1062      while ($res = $result->fetchRow()) 
1063      {
1064        //candidates store activities we can reach from our running activity
1065        $candidates[] = $res['wf_act_to_id'];
1066      }  
1067      if($type == 'split') 
1068      {
1069        $erase_from = false;
1070        $num_candidates = count($candidates);
1071        $returned_data = Array();
1072        $i = 1;
1073        foreach ($candidates as $cand) 
1074        {
1075          // only erase split activity in instance when all the activities comming from the split have been set up
1076          if ($i == $num_candidates)
1077          { 
1078            $erase_from = true;
1079          }
1080          $returned_data[$i] = $this->sendTo($activityId,$cand,$erase_from);
1081          $i++;
1082        }
1083        return $returned_data;
1084      } 
1085      elseif($type == 'switch') 
1086      {
1087        if (in_array($this->nextActivity[$activityId],$candidates))
1088        {
1089          return $this->sendTo((int)$activityId,(int)$this->nextActivity[$activityId]);
1090        } 
1091        else 
1092        {
1093          $returned_value['transition']['failure'] = tra('Error: nextActivity does not match any candidate in autorouting switch activity');
1094          return $returned_value;
1095        }
1096      } 
1097      else 
1098      {
1099        if (count($candidates)>1) 
1100        {
1101          $returned_value['transition']['failure'] = tra('Error: non-deterministic decision for autorouting activity');
1102          return $returned_value;
1103        }
1104        else 
1105        {
1106          return $this->sendTo((int)$activityId,(int)$candidates[0]);
1107        }
1108      }
1109    }
1110    
1111    /*!
1112    * This is a semi-private function, use GUI's abort function
1113    * Aborts an activity and terminates the whole instance. We still create a workitem to keep track
1114    * of where in the process the instance was aborted
1115    * TODO: review, reuse of completed code
1116    */
1117    function abort($activityId=0,$theuser = '',$addworkitem=true) 
1118    {
1119      if(empty($theuser)) {
1120        global $user;
1121        if (empty($user)) {$theuser='*';} else {$theuser=$user;}
1122      }
1123      
1124      if($activityId==0) {
1125        $activityId=$_REQUEST['wf_activity_id'];
1126      }  
1127      
1128      // If we are aborting a start activity then the instance must 
1129      // be created first!
1130      // ==> No, there's no reason to have an uncompleted start activity to abort
1131      $type = $this->getOne('select wf_type from '.GALAXIA_TABLE_PREFIX.'activities where wf_activity_id=?',array((int)$activityId));    
1132  
1133      // Now set ended on instance_activities
1134      $now = date("U");
1135      $query = 'update '.GALAXIA_TABLE_PREFIX.'instance_activities set wf_ended=? where wf_activity_id=? and wf_instance_id=?';
1136      $this->query($query,array((int)$now,(int)$activityId,(int)$this->instanceId));
1137  
1138      //Set the status for the instance-activity to aborted
1139  
1140      // terminate the instance with status 'aborted'
1141      if (!($this->terminate($now,'aborted'))) return false;
1142  
1143      //now we synchronise instance with the database
1144          //echo "<br/> syncing  in abort";
1145      if (!($this->sync())) return false;
1146      
1147      //Add a workitem to the instance 
1148      if ($addworkitem)
1149      {
1150        return $this->addworkitem($type,$now, $activityId);
1151      }
1152      else
1153      {
1154        return true;
1155      }
1156    }
1157    
1158    /*!
1159    * @private
1160    * Terminates the instance marking the instance and the process
1161    * as completed. This is the end of a process.
1162    * Normally you should not call this method since it is automatically
1163    * called when an end activity is completed.
1164    * object is synched at the end of this function.
1165    * @param $time is the terminating time
1166    * @param $status is the final status, 'completed' by default
1167    * @return true if everything was ok, false else
1168    */
1169    function terminate($time, $status = 'completed') {
1170      //Set the status of the instance to completed
1171      if (!($this->setEnded((int)$time))) return false;
1172      if (!($this->setStatus($status))) return false;
1173      $query = "delete from `".GALAXIA_TABLE_PREFIX."instance_activities` where `wf_instance_id`=?";
1174      $this->query($query,array((int)$this->instanceId));
1175          //echo "<br/> syncing  in terminate";
1176      return $this->sync();
1177    }
1178    
1179    
1180    /*!
1181    * Sends the instance from some activity to another activity. (walk on a transition)
1182    * You should not call this method unless you know very very well what
1183    * you are doing.
1184    * @param $from is the activity id at the start of the transition
1185    * @param $activityId is the activity id at the end of the transition
1186    * @param $erase_from is true by default, if true the coming activity row will be erased from
1187    * instance_activities table. You should set it to false for example with split activities while
1188    * you still want to re-call this function
1189    * @return false if anything goes wrong, true if we are at the end of the execution tree and an array
1190    * if a part of the process was automatically runned at the end of the transition. this array contains
1191    * 2 keys 'transition' is the transition we walked on, 'activity' is the result of the run part if it was an automatic activity.
1192    * 'activity' value is an associated array containing several usefull keys:
1193    *    * 'completed' is a boolean indicating that the activity was completed or not
1194    *    * 'debug contains debug messages
1195    *    * 'info' contains some usefull infos about the activity-instance running (like names)
1196    *    * 'next' is the result of a SendAutorouted part which could in fact be the result of a call to this function, etc.
1197    */
1198    function sendTo($from,$activityId,$erase_from=true) 
1199    {
1200      //we will use an array for return value
1201      $returned_data = Array();
1202      //1: if we are in a join check
1203      //if this instance is also in
1204      //other activity if so do
1205      //nothing
1206      $query = 'select wf_type, wf_name from '.GALAXIA_TABLE_PREFIX.'activities where wf_activity_id=?';
1207      $result = $this->query($query,array($activityId));
1208      if (empty($result))
1209      {
1210        $returned_data['transition']['failure'] = tra('Error: trying to send an instance to an activity but it was impossible to get this activity');
1211        return $returned_data;
1212      }
1213      while ($res = $result->fetchRow())
1214      {
1215        $type = $res['wf_type'];
1216        $targetname = $res['wf_name'];
1217      }
1218      $returned_data['transition']['target_id'] = $activityId;
1219      $returned_data['transition']['target_name'] = $targetname;
1220      
1221      // Verify the existence of a transition
1222      if(!$this->getOne("select count(*) from `".GALAXIA_TABLE_PREFIX."transitions` where `wf_act_from_id`=? and `wf_act_to_id`=?",array($from,(int)$activityId))) {
1223        $returned_data['transition']['failure'] = tra('Error: trying to send an instance to an activity but no transition found');
1224        return $returned_data;
1225      }
1226  
1227      //init
1228      $putuser=0;
1229      
1230      //try to determine the user or *
1231      //Use the nextUser
1232      $the_next_user = $this->getNextUser();
1233      if($the_next_user) 
1234      {
1235        //we check rights for this user on the next activity
1236        if (!(isset($this->security))) $this->security =& new WfSecurity($this->db); 
1237        if ($this->security->checkUserAccess($the_next_user,$activityId))
1238        {
1239          $putuser = $the_next_user;
1240        }
1241      }
1242      if ($putuser==0)
1243      {
1244        // If no nextUser is set, then see if only
1245        // one user is in the role for this activity
1246        // and assign ownership to him if this is the case
1247        $query = "select `wf_role_id` from `".GALAXIA_TABLE_PREFIX."activity_roles` where `wf_activity_id`=?";
1248        $result = $this->query($query,array((int)$activityId)); 
1249        while ($res = $result->fetchRow()) 
1250        {
1251          $roleId = $res['wf_role_id'];
1252          //regis: group role mapping as an impact here, we need to count real user corresponding to this role
1253          // and we obtain users 'u' and groups 'g' in user_roles
1254          // we consider number of members on each group is subject to too much changes and so we do not even try 
1255          // to look in members of the group to find if there is a unique real user candidate for this role
1256          // you could try it if you want but it's quite complex for something not really usefull
1257          // if there's at least one group in the roles we then won't even try to get this unique user
1258          $query_group = "select count(*) from ".GALAXIA_TABLE_PREFIX."user_roles 
1259              where wf_role_id=? and wf_account_type='g'";
1260          if ($this->getOne($query_group,array((int)$roleId)) > 0 )
1261          { //we have groups
1262            //we can break the while, we wont search the candidate
1263            $putuser=0;
1264            break;
1265          }
1266          else
1267          {// we have no groups
1268            $query2 = "select distinct wf_user, wf_account_type from ".GALAXIA_TABLE_PREFIX."user_roles 
1269                where wf_role_id=?";
1270            $result2 = $this->query($query2,array((int)$roleId)); 
1271            while ($res2 = $result2->fetchRow()) 
1272            {
1273              if (!($putuser==0))
1274              { // we already have one candidate
1275                // we have another one in $res2['wf_user'] but it means we don't have only one
1276                // we can unset our job and break the wile
1277                $putuser=0;
1278                break;
1279              }
1280              else
1281              {
1282                // set the first candidate
1283                $putuser = $res2['wf_user'];
1284              }
1285            }
1286          }
1287        }
1288  
1289        if ($putuser==0) // no decisions yet
1290        {
1291          // then check to see if there is a default user
1292          $activity_manager =& new ActivityManager($this->db);
1293          //get_default_user will give us '*' if there is no default_user or if the default user has no role
1294          //mapped anymore
1295          $default_user = $activity_manager->get_default_user($activityId,true);
1296          unset($activity_manager);
1297          // if they were no nextUser, no unique user avaible, no default_user then we'll have '*'
1298          // which will let user having the good role mapping grab this activity later
1299          $putuser = $default_user;
1300        }
1301      }
1302      
1303      //update the instance_activities table
1304      //if not splitting delete first
1305      //please update started,status,user
1306      if (($erase_from) && (!empty($this->instanceId)))
1307      {
1308        $query = "delete from `".GALAXIA_TABLE_PREFIX."instance_activities` where `wf_instance_id`=? and `wf_activity_id`=?";
1309        $this->query($query,array((int)$this->instanceId,$from));
1310      }
1311    
1312      if ($type == 'join') {
1313        if (count($this->activities)>1) {
1314          // This instance will have to wait!
1315          $returned_data['transition']['status'] = 'waiting';
1316          return $returned_data;
1317        }
1318      }    
1319  
1320      //create the new instance-activity
1321      $returned_data['transition']['target_id'] = $activityId;
1322      $returned_data['transition']['target_name'] = $targetname;
1323      $now = date("U");
1324      $iid = $this->instanceId;
1325      $query="delete from `".GALAXIA_TABLE_PREFIX."instance_activities` where `wf_instance_id`=? and `wf_activity_id`=?";
1326      $this->query($query,array((int)$iid,(int)$activityId));
1327      $query="insert into `".GALAXIA_TABLE_PREFIX."instance_activities`(`wf_instance_id`,`wf_activity_id`,`wf_user`,`wf_status`,`wf_started`) values(?,?,?,?,?)";
1328      $this->query($query,array((int)$iid,(int)$activityId,$putuser,'running',(int)$now));
1329      
1330      //record the transition walk
1331      $returned_data['transition']['status'] = 'done';
1332  
1333      
1334      //we are now in a new activity
1335      $this->_populate_activities($iid);
1336      //if the activity is not interactive then
1337      //execute the code for the activity and
1338      //complete the activity
1339      $isInteractive = $this->getOne("select `wf_is_interactive` from `".GALAXIA_TABLE_PREFIX."activities` where `wf_activity_id`=?",array((int)$activityId));
1340      if ($isInteractive=='n') 
1341      {
1342        //first we sync actual instance because the next activity could need it
1343          //echo "<br/> syncing  in sendTo 1";
1344        if (!($this->sync()))
1345        {
1346          $returned_data['activity']['failure'] = true;
1347          return $returned_data;
1348        }
1349        // Now execute the code for the activity
1350        $returned_data['activity'] = $this->executeAutomaticActivity($activityId, $iid);
1351      }
1352      else
1353      {
1354        // we sync actual instance
1355          //echo "<br/> syncing  in sendTo 2";
1356        if (!($this->sync()))
1357        {
1358          $returned_data['failure'] = true;
1359          return $returned_data;
1360        }
1361      }
1362      return $returned_data;
1363    }
1364    
1365    /*!
1366    * @public
1367    * This is a public method only because the GUI can ask this action for the admin
1368    * on restart failed automated activities, but in fact it's quite an internal function,
1369    * This function handle the execution of automatic activities (and the launch of transitions
1370    * which can be related to this activity).
1371    * @param $activityId is the activity id at the end of the transition
1372    * @param $iid is the instance id
1373    */
1374    function executeAutomaticActivity($activityId, $iid)
1375    {
1376      $returned_data = Array();
1377      // Now execute the code for the activity (function defined in galaxia's config.php)
1378      // echo "<br />execute automatic activity";
1379      $returned_data =& galaxia_execute_activity($activityId, $iid , 1);
1380  
1381      //we should have some info in $returned_data now. if it is false there's a problem
1382      if ((!(is_array($returned_data))) && (!($returned_data)) )
1383      {
1384        $this->error[] = tra('failed to execute automatic activity');
1385        //record the failure
1386        $returned_data['failure'] = true;
1387        return $returned_data;
1388      }
1389      else
1390      {
1391        //ok, we have an array, but it can still be a bad result
1392        //this one is just for debug info
1393        if (isset($returned_data['debug']))
1394        {
1395          //we retrieve this info here, in this object
1396          $this->error[] = $returned_data['debug'];
1397        }
1398        //and this really test if it worked, if not we have a nice failure message (better than just failure=true)
1399        if (isset($returned_data['failure']))
1400        {
1401          $this->error[] = tra('failed to execute automatic activity');
1402          $this->error[] = $returned_data['failure'];
1403          //record the failure
1404          return $returned_data;
1405        }
1406        
1407      }
1408      // Reload in case the activity did some change, last sync was done just before calling this function
1409      // regis: need a sync here, not just a reload from database
1410          //echo "<br/> syncing  in ExecuteAutomaticActivity";
1411      $this->unsynch=true; //we force unsynch state as this will force sync() to reload data
1412      $this->sync();
1413  
1414      //complete the automatic activity----------------------------
1415      if ($this->Complete($activityId))
1416      {
1417        $returned_data['completed'] = true;
1418        
1419        //and send the next autorouted activity if any
1420        $returned_data['next'] = $this->sendAutorouted($activityId);
1421      }
1422      else
1423      {
1424        $returned_data['failure'] = $this->get_error();
1425      }
1426      return $returned_data;
1427    }
1428    
1429    /*! 
1430    Gets a comment for this instance 
1431    */
1432    function get_instance_comment($cId) {
1433      $iid = $this->instanceId;
1434      $query = "select * from `".GALAXIA_TABLE_PREFIX."instance_comments` where `wf_instance_id`=? and `wf_c_id`=?";
1435      $result = $this->query($query,array((int)$iid,(int)$cId));
1436      $res = $result->fetchRow();
1437      return $res;
1438    }
1439    
1440    /*! 
1441    Inserts or updates an instance comment 
1442    */
1443    function replace_instance_comment($cId, $activityId, $activity, $user, $title, $comment) {
1444      if (!$user) {
1445        $user = 'Anonymous';
1446      }
1447      $iid = $this->instanceId;
1448      //no need on pseudo-instance
1449      if (!!($this->instanceId))
1450      {
1451        if ($cId) 
1452        {
1453          $query = "update `".GALAXIA_TABLE_PREFIX."instance_comments` set `wf_title`=?,`wf_comment`=? where `wf_instance_id`=? and `wf_c_id`=?";
1454          $this->query($query,array($title,$comment,(int)$iid,(int)$cId));
1455        } 
1456        else 
1457        {
1458          $hash = md5($title.$comment);
1459          if ($this->getOne("select count(*) from `".GALAXIA_TABLE_PREFIX."instance_comments` where `wf_instance_id`=? and `wf_hash`=?",array($iid,$hash))) 
1460          {
1461            return false;
1462          }
1463          $now = date("U");
1464          $query ="insert into `".GALAXIA_TABLE_PREFIX."instance_comments`(`wf_instance_id`,`wf_user`,`wf_activity_id`,`wf_activity`,`wf_title`,`wf_comment`,`wf_timestamp`,`wf_hash`) values(?,?,?,?,?,?,?,?)";
1465          $this->query($query,array((int)$iid,$user,(int)$activityId,$activity,$title,$comment,(int)$now,$hash));
1466        }
1467      }
1468      return true;
1469    }
1470    
1471    /*!
1472    Removes an instance comment
1473    */
1474    function remove_instance_comment($cId) {
1475      $iid = $this->instanceId;
1476      $query = "delete from `".GALAXIA_TABLE_PREFIX."instance_comments` where `wf_c_id`=? and `wf_instance_id`=?";
1477      $this->query($query,array((int)$cId,(int)$iid));
1478    }
1479   
1480    /*!
1481    Lists instance comments
1482    */
1483    function get_instance_comments() {
1484      $iid = $this->instanceId;
1485      $query = "select * from `".GALAXIA_TABLE_PREFIX."instance_comments` where `wf_instance_id`=? order by ".$this->convert_sortmode("timestamp_desc");
1486      $result = $this->query($query,array((int)$iid));    
1487      $ret = Array();
1488      while($res = $result->fetchRow()) {    
1489        $ret[] = $res;
1490      }
1491      return $ret;
1492    }
1493  }
1494  ?>


Généré le : Sun Feb 25 17:20:01 2007 par Balluche grâce à PHPXref 0.7