[ Index ] |
|
Code source de eGroupWare 1.2.106-2 |
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 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sun Feb 25 17:20:01 2007 | par Balluche grâce à PHPXref 0.7 |