Changeset 2129 for sandbox/workflow/branches/603/inc/engine
- Timestamp:
- 03/02/10 13:54:12 (15 years ago)
- Location:
- sandbox/workflow/branches/603/inc/engine/src
- Files:
-
- 2 deleted
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
sandbox/workflow/branches/603/inc/engine/src/ProcessManager/ProcessManager.php
r795 r2129 4 4 * Adds, removes, modifies and lists processes. 5 5 * Most of the methods acts directly in database level, bypassing Project object methods 6 * 6 * 7 7 * @todo Fix multiple non checked fopen ==> infinite loops in case of problems with filesystem 8 8 * @package Galaxia 9 * @license http://www.gnu.org/copyleft/gpl.html GPL 9 * @license http://www.gnu.org/copyleft/gpl.html GPL 10 10 */ 11 11 class ProcessManager extends BaseManager { 12 13 /** 14 * @var resource $parser xml parser 15 * @access public 16 */ 17 var $parser; 18 19 /** 20 * @var array $tree data struture 21 * @access public 22 */ 23 var $tree; 24 25 /** 26 * @var $current current element 27 * @access public 28 */ 29 var $current; 30 31 /** 32 * @var $buffer buffer for data 33 * @access public 34 */ 35 var $buffer; 36 37 /** 38 * @var object $Process Process 39 * @access public 40 */ 41 var $Process; 42 43 /** 44 * @var object $activity_manager Activity Manager 45 * @access public 46 */ 47 var $activity_manager; 48 49 /** 50 * @var object $jobManager Job Manager object 51 * @access public 52 */ 53 var $jobManager; 54 55 /** 56 * @var object $role_manager Role Manager 57 * @access public 58 */ 59 var $role_manager; 60 61 /** 62 * Constructor 63 * 64 * @param object &$db ADOdb 65 * @return object ProcessManager 66 * @access public 67 */ 68 function ProcessManager(&$db) 69 { 70 parent::BaseManager($db); 71 $this->child_name = 'ProcessManager'; 72 require_once(GALAXIA_LIBRARY.SEP.'src'.SEP.'ProcessManager'.SEP.'ActivityManager.php'); 73 require_once(GALAXIA_LIBRARY.SEP.'src'.SEP.'ProcessManager'.SEP.'JobManager.php'); 74 // $this->activity_manager is not set here to avoid objects loading object A loading object B loading object A, etc 75 //$this->role_manager will only be loaded when needed as well 76 } 77 78 /** 79 * Collect errors from all linked objects which could have been used by this object. 80 * Each child class should instantiate this function with her linked objetcs, calling get_error(true) 81 * 82 * @param bool $debug False by default, if true debug messages can be added to 'normal' messages 83 * @param string $prefix Appended to the debug message 84 * @return void 85 * @access public 86 */ 87 function collect_errors($debug=false, $prefix = '') 88 { 89 parent::collect_errors($debug, $prefix); 90 if (isset($this->activity_manager)) $this->error[] = $this->activity_manager->get_error(false, $debug, $prefix); 91 if (isset($this->role_manager)) $this->error[] = $this->role_manager->get_error(false, $debug, $prefix); 92 } 93 94 /** 95 * Activates a process 96 * 97 * @param int $pId Process id 98 * @return void 99 * @access public 100 */ 101 function activate_process($pId) 102 { 103 $query = 'update '.GALAXIA_TABLE_PREFIX.'processes set wf_is_active=? where wf_p_id=?'; 104 $this->query($query, array('y',$pId)); 105 $msg = sprintf(tra('Process %d has been activated'),$pId); 106 $this->notify_all(3,$msg); 107 $this->error[] = $msg; 108 } 109 110 /** 111 * Deactivates a process 112 * 113 * @param int $pId Process id 114 * @return void 115 * @access public 116 */ 117 function deactivate_process($pId) 118 { 119 $query = 'update '.GALAXIA_TABLE_PREFIX.'processes set wf_is_active=? where wf_p_id=?'; 120 $this->query($query, array('n',$pId)); 121 $msg = sprintf(tra('Process %d has been deactivated'),$pId); 122 $this->notify_all(3,$msg); 123 $this->error[] = $msg; 124 } 125 126 /** 127 * Creates an XML representation of a process 128 * 129 * @param int $pId Process id 130 * @return string 131 * @access public 132 */ 133 function serialize_process($pId) 134 { 135 if (!(isset($this->activity_manager))) $this->activity_manager = new ActivityManager($this->db); 136 // <process> 137 $out = '<process>'."\n"; 138 //we retrieve config values with the others process data 139 $proc_info =& $this->get_process($pId, true); 140 $wf_procname = $proc_info['wf_normalized_name']; 141 $out.= ' <name>'.htmlspecialchars($proc_info['wf_name']).'</name>'."\n"; 142 $out.= ' <isValid>'.htmlspecialchars($proc_info['wf_is_valid']).'</isValid>'."\n"; 143 $out.= ' <version>'.htmlspecialchars($proc_info['wf_version']).'</version>'."\n"; 144 $out.= ' <isActive>'.htmlspecialchars($proc_info['wf_is_active']).'</isActive>'."\n"; 145 $out.=' <description>'.htmlspecialchars($proc_info['wf_description']).'</description>'."\n"; 146 $out.= ' <lastModif>'.date("d/m/Y [h:i:s]",$proc_info['wf_last_modif']).'</lastModif>'."\n"; 147 148 //Shared code 149 $out.= ' <sharedCode><![CDATA['; 150 $fp=fopen(GALAXIA_PROCESSES.SEP."$wf_procname".SEP."code".SEP."shared.php","r"); 151 while(!feof($fp)) { 152 $line=fread($fp,8192); 153 $out.=$line; 154 } 155 fclose($fp); 156 $out.= ' ]]></sharedCode>'."\n"; 157 158 //Loop on config values 159 $out.=' <configs>'."\n"; 160 foreach($proc_info['config'] as $res) { 161 $name = $res['wf_config_name']; 162 $value_int = $res['wf_config_value_int']; 163 $value = $res['wf_config_value']; 164 $out.=' <config>'."\n"; 165 $out.=' <wf_config_name>'.htmlspecialchars($name).'</wf_config_name>'."\n"; 166 $out.=' <wf_config_value>'.htmlspecialchars($value).'</wf_config_value>'."\n"; 167 $out.=' <wf_config_value_int>'.htmlspecialchars($value_int).'</wf_config_value_int>'."\n"; 168 $out.=' </config>'."\n"; 169 } 170 $out.=' </configs>'."\n"; 171 172 // Now loop over activities 173 $query = "select * from ".GALAXIA_TABLE_PREFIX."activities where wf_p_id=$pId"; 174 $result = $this->query($query); 175 $out.=' <activities>'."\n"; 176 while($res = $result->fetchRow()) { 177 $name = $res['wf_normalized_name']; 178 $out.=' <activity>'."\n"; 179 $out.=' <name>'.htmlspecialchars($res['wf_name']).'</name>'."\n"; 180 $out.=' <type>'.htmlspecialchars($res['wf_type']).'</type>'."\n"; 181 $out.=' <description>'.htmlspecialchars($res['wf_description']).'</description>'."\n"; 182 $out.=' <lastModif>'.date("d/m/Y [h:i:s]",$res['wf_last_modif']).'</lastModif>'."\n"; 183 $out.=' <isInteractive>'.$res['wf_is_interactive'].'</isInteractive>'."\n"; 184 $out.=' <isAutoRouted>'.$res['wf_is_autorouted'].'</isAutoRouted>'."\n"; 185 $out.=' <roles>'."\n"; 186 //loop on activity roles 187 $actid = $res['wf_activity_id']; 188 $roles =& $this->activity_manager->get_activity_roles($actid); 189 foreach($roles as $role) { 190 if ($role['wf_readonly']) 191 { 192 $out.=' <role readonly="true">'.htmlspecialchars($role['wf_name']).'</role>'."\n"; 193 } 194 else 195 { 196 $out.=' <role>'.htmlspecialchars($role['wf_name']).'</role>'."\n"; 197 } 198 } 199 $out.=' </roles>'."\n"; 200 $out.=' <agents>'."\n"; 201 //loop on activity agents 202 $agents =& $this->activity_manager->get_activity_agents($actid); 203 foreach($agents as $agent) { 204 $out.=' <agent>'."\n"; 205 $out.=' <agent_type>'.htmlspecialchars($agent['wf_agent_type']).'</agent_type>'."\n"; 206 //loop on agent datas 207 $agent_data =& $this->activity_manager->get_activity_agent_data($actid,$agent['wf_agent_type']); 208 $out.=' <agent_datas>'."\n"; 209 foreach($agent_data as $key => $value) 210 { 211 if (!($key=='wf_agent_id')) 212 { 213 $out.=' <agent_data>'."\n"; 214 $out.=' <name>'.htmlspecialchars($key).'</name>'."\n"; 215 $out.=' <value>'.htmlspecialchars($value).'</value>'."\n"; 216 $out.=' </agent_data>'."\n"; 217 } 218 } 219 $out.=' </agent_datas>'."\n"; 220 $out.=' </agent>'."\n"; 221 } 222 $out.=' </agents>'."\n"; 223 224 //the code 225 $out.=' <code><![CDATA['; 226 $fp=fopen(GALAXIA_PROCESSES.SEP."$wf_procname".SEP."code".SEP."activities".SEP."$name.php","r"); 227 while(!feof($fp)) { 228 $line=fread($fp,8192); 229 $out.=$line; 230 } 231 fclose($fp); 232 $out.=' ]]></code>'; 233 if($res['wf_is_interactive']=='y') { 234 $out.=' <template><![CDATA['; 235 $fp=fopen(GALAXIA_PROCESSES.SEP."$wf_procname".SEP."code".SEP."templates".SEP."$name.tpl","r"); 236 while(!feof($fp)) { 237 $line=fread($fp,8192); 238 $out.=$line; 239 } 240 fclose($fp); 241 $out.=' ]]></template>'; 242 } 243 $out.=' </activity>'."\n"; 244 } 245 $out.=' </activities>'."\n"; 246 $out.=' <transitions>'."\n"; 247 //loop on transitions 248 $transitions = $this->activity_manager->get_process_transitions($pId); 249 foreach($transitions as $tran) { 250 $out.=' <transition>'."\n"; 251 $out.=' <from>'.htmlspecialchars($tran['wf_act_from_name']).'</from>'."\n"; 252 $out.=' <to>'.htmlspecialchars($tran['wf_act_to_name']).'</to>'."\n"; 253 $out.=' </transition>'."\n"; 254 } 255 $out.=' </transitions>'."\n"; 256 $out.= '</process>'."\n"; 257 //$fp = fopen(GALAXIA_PROCESSES."/$wf_procname/$wf_procname.xml","w"); 258 //fwrite($fp,$out); 259 //fclose($fp); 260 return $out; 261 } 262 263 /** 264 * Creates a process PHP data structure from its XML representation 265 * 266 * @param string &$xml XML document 267 * @return array Process data structure 268 * @access public 269 */ 270 function unserialize_process(&$xml) 271 { 272 // Create SAX parser assign this object as base for handlers 273 // handlers are private methods defined below. 274 // keep contexts and parse 275 $this->parser = xml_parser_create(); 276 xml_parser_set_option($this->parser,XML_OPTION_CASE_FOLDING,0); 277 //xml_parser_set_option($parser,XML_OPTION_SKIP_WHITE, 1); 278 xml_set_object($this->parser, $this); 279 xml_set_element_handler($this->parser, '_start_element_handler', '_end_element_handler'); 280 xml_set_character_data_handler($this->parser, '_data_handler'); 281 $aux=Array( 282 'name'=>'root', 283 'children'=>Array(), 284 'parent' => 0, 285 'data'=>'', 286 'attribs' => Array(), 287 ); 288 $this->tree[0]=$aux; 289 $this->current=0; 290 291 292 if (!xml_parse($this->parser, $xml, true)) { 293 $error = sprintf("XML error: %s at line %d", 294 xml_error_string(xml_get_error_code($this->parser)), 295 xml_get_current_line_number($this->parser)); 296 trigger_error($error,E_USER_WARNING); 297 $this->error[] = $error; 298 } 299 xml_parser_free($this->parser); 300 // Now that we have the tree we can do interesting things 301 302 $process=Array(); 303 $activities=Array(); 304 $transitions=Array(); 305 for($i=0;$i<count($this->tree[1]['children']);$i++) { 306 // Process attributes 307 $z=$this->tree[1]['children'][$i]; 308 $name = trim($this->tree[$z]['name']); 309 310 //config values 311 if ($name=='configs') { 312 for($j=0;$j<count($this->tree[$z]['children']);$j++) { 313 $z2 = $this->tree[$z]['children'][$j]; 314 // this is a config $name = $this->tree[$z2]['name']; 315 $aux = Array(); 316 if($this->tree[$z2]['name']=='config') { 317 for($k=0;$k<count($this->tree[$z2]['children']);$k++) { 318 $z3 = $this->tree[$z2]['children'][$k]; 319 $name = trim($this->tree[$z3]['name']); 320 $value= trim($this->tree[$z3]['data']); 321 $aux[$name]=$value; 322 } 323 $configs[]=$aux; 324 } 325 } 326 } 327 //activities 328 elseif($name=='activities') { 329 for($j=0;$j<count($this->tree[$z]['children']);$j++) { 330 $z2 = $this->tree[$z]['children'][$j]; 331 // this is an activity $name = $this->tree[$z2]['name']; 332 $aux = Array(); 333 if($this->tree[$z2]['name']=='activity') { 334 for($k=0;$k<count($this->tree[$z2]['children']);$k++) { 335 $z3 = $this->curre[$z2]['children'][$k]; 336 $name = trim($this->tree[$z3]['name']); 337 $value= trim($this->tree[$z3]['data']); 338 if($name=='roles') { 339 $roles=Array(); 340 for($l=0;$l<count($this->tree[$z3]['children']);$l++) { 341 $z4 = $this->tree[$z3]['children'][$l]; 342 $name = trim($this->tree[$z4]['name']); 343 $data = trim($this->tree[$z4]['data']); 344 $attribs = $this->tree[$z4]['attribs']; 345 $readonly = false; 346 if ( (isset($attribs['readonly'])) && ($attribs['readonly'])) 347 { 348 //role in read-only 349 $readonly = true; 350 } 351 $roles[]=array( 352 'name' => $data, 353 'readonly' => $readonly, 354 ); 355 } 356 } 357 elseif ($name=='agents') 358 { 359 $agents=Array(); 360 for($l=0;$l<count($this->tree[$z3]['children']);$l++) 361 { 362 $z4 = $this->tree[$z3]['children'][$l]; 363 //$name is agent 364 $name = trim($this->tree[$z4]['name']); 365 if ($name = 'agent') 366 { 367 $agent = array(); 368 for($m=0;$m<count($this->tree[$z4]['children']);$m++) 369 { 370 $z5 = $this->tree[$z4]['children'][$m]; 371 //$name is agent_type or agent_datas 372 $name = trim($this->tree[$z5]['name']); 373 // data will be the agent_type or an array for agent_datas 374 $data = trim($this->tree[$z5]['data']); 375 if ($name=='agent_type') 376 { 377 $agent['wf_agent_type']=$data; 378 } 379 elseif ($name=='agent_datas') 380 { 381 for($n=0;$n<count($this->tree[$z5]['children']);$n++) 382 { 383 $z6 = $this->tree[$z5]['children'][$n]; 384 //$name is agent_data $val is an array 385 $name = trim($this->tree[$z6]['name']); 386 $val = trim($this->tree[$z6]['data']); 387 if ($name=='agent_data') 388 { 389 for($o=0;$o<count($this->tree[$z6]['children']);$o++) 390 { 391 $z7 = $this->tree[$z6]['children'][$o]; 392 //$name is agent_data $val is 'name' or 'value' 393 $name = trim($this->tree[$z7]['name']); 394 $content = trim($this->tree[$z7]['data']); 395 //echo "<br>z7 name $name content: $content"; 396 if ($name=='name') 397 { 398 $agent_data_name = $content; 399 } 400 elseif ($name=='value') 401 { 402 $agent_data_value =& $content; 403 } 404 } 405 //echo "<br>associate $agent_data_name to $agent_data_value <hr>"; 406 $agent[$agent_data_name] = $agent_data_value; 407 } 408 } 409 } 410 } 411 $agents[]=$agent; 412 } 413 } 414 } else { 415 $aux[$name]=$value; 416 //print("$name:$value<br/>"); 417 } 418 } 419 $aux['agents']=$agents; 420 $aux['roles']=$roles; 421 $activities[]=$aux; 422 } 423 } 424 } elseif($name=='transitions') { 425 for($j=0;$j<count($this->tree[$z]['children']);$j++) { 426 $z2 = $this->tree[$z]['children'][$j]; 427 // this is an activity $name = $this->tree[$z2]['name']; 428 $aux=Array(); 429 if($this->tree[$z2]['name']=='transition') { 430 for($k=0;$k<count($this->tree[$z2]['children']);$k++) { 431 $z3 = $this->tree[$z2]['children'][$k]; 432 $name = trim($this->tree[$z3]['name']); 433 $value= trim($this->tree[$z3]['data']); 434 if($name == 'from' || $name == 'to') { 435 $aux[$name]=$value; 436 } 437 } 438 } 439 $transitions[] = $aux; 440 } 441 } else { 442 $value = trim($this->tree[$z]['data']); 443 //print("$name is $value<br/>"); 444 $process[$name]=$value; 445 } 446 } 447 $process['configs']=$configs; 448 $process['activities']=$activities; 449 $process['transitions']=$transitions; 450 return $process; 451 } 452 453 /** 454 * Creates a process from the process data structure, if you want to convert an XML to a process then use first unserialize_process and then this method. 455 * 456 * @access public 457 * @param string &$data 458 * @return bool 459 */ 460 function import_process(&$data) 461 { 462 //Now the show begins 463 if (!(isset($this->activity_manager))) $this->activity_manager = new ActivityManager($this->db); 464 if (!(isset($this->role_manager))) $this->role_manager = new RoleManager($this->db); 465 if (!isset($this->jobManager)) 466 $this->jobManager = new JobManager($this->db); 467 468 // First create the process. Always inactive and inactive first. 469 $vars = Array( 470 'wf_name' => trim($data['name']), 471 'wf_version' => $data['version'], 472 'wf_description' => $data['description'], 473 'wf_last_modif' => $data['lastModif'], 474 'wf_is_active' => false, 475 'wf_is_valid' => false, 476 'config' => $data['configs'], 477 ); 478 479 if (empty($vars['wf_name'])) 480 { 481 $msg = tra('invalid name specified'); 482 $this->notify_all(2,$msg); 483 $this->error[] = $msg; 484 return false; 485 } 486 487 if (ereg('^[0-9]{1,2}\.[0-9]{1,2}$', $vars['wf_version']) === false) 488 { 489 $msg = tra('invalid version specified'); 490 $this->notify_all(2,$msg); 491 $this->error[] = $msg; 492 return false; 493 } 494 495 if ($this->process_name_exists($vars['wf_name'], $vars['wf_version'])) 496 { 497 $msg = sprintf(tra('Process %s %s already exists, the import process was aborted'),$vars['wf_name'],$vars['wf_version']); 498 $this->notify_all(2,$msg); 499 $this->error[] = $msg; 500 return false; 501 } 502 $pid = $this->replace_process(0,$vars,false); 503 //Put the shared code 504 $proc_info = $this->get_process($pid); 505 $wf_procname = $proc_info['wf_normalized_name']; 506 $fp = fopen(GALAXIA_PROCESSES.SEP.$wf_procname.SEP.'code'.SEP.'shared.php',"w"); 507 fwrite($fp, $data['sharedCode']); 508 fclose($fp); 509 $actids = Array(); 510 511 // Foreach activity create activities 512 foreach($data['activities'] as $activity) { 513 514 $vars = Array( 515 'wf_name' => $activity['name'], 516 'wf_description' => $activity['description'], 517 'wf_type' => $activity['type'], 518 'wf_menu_path' => $activity['menuPath'], 519 'wf_last_modif' => $activity['lastModif'], 520 'wf_is_interactive' => $activity['isInteractive'], 521 'wf_is_autorouted' => $activity['isAutoRouted'] 522 ); 523 $actname=$this->activity_manager->_normalize_name($activity['name']); 524 $actid = $this->activity_manager->replace_activity($pid,0,$vars); 525 526 $fp = fopen(GALAXIA_PROCESSES.SEP.$wf_procname.SEP.'code'.SEP.'activities'.SEP.$actname.'.php',"w"); 527 fwrite($fp, $activity['code']); 528 fclose($fp); 529 if($activity['isInteractive']=='y') { 530 $fp = fopen(GALAXIA_PROCESSES.SEP.$wf_procname.SEP.'code'.SEP.'templates'.SEP.$actname.'.tpl',"w"); 531 fwrite($fp,$activity['template']); 532 fclose($fp); 533 } 534 $actids[$activity['name']] = $this->activity_manager->_get_activity_id_by_name($pid, $activity['name']); 535 $actname = $this->activity_manager->_normalize_name($activity['name']); 536 $now = date("U"); 537 //roles 538 if( is_array($activity['roles']) && count($activity['roles']) > 0 ) 539 { 540 foreach($activity['roles'] as $role) 541 { 542 $rolename = $role['name']; 543 $vars = Array( 544 'wf_name' => $rolename, 545 'wf_description' => $rolename, 546 'wf_last_modif' => $now, 547 ); 548 if(!$this->role_manager->role_name_exists($pid,$rolename)) { 549 $rid=$this->role_manager->replace_role($pid,0,$vars); 550 } else { 551 $rid = $this->role_manager->get_role_id($pid,$rolename); 552 } 553 if($actid && $rid) { 554 $this->activity_manager->add_activity_role($actid,$rid,$role['readonly']); 555 } 556 } 557 } 558 //agents 559 if( is_array($activity['agents']) && count($activity['agents']) > 0 ) 560 { 561 foreach($activity['agents'] as $agent) 562 { 563 if (empty($agent['wf_agent_type'])) 564 { 565 $this->error[] = lang('empty agent type'); 566 } 567 else 568 { 569 //create a new agent of the same type for the new activity 570 $agentid = $this->activity_manager->add_activity_agent($actid,$agent['wf_agent_type']); 571 //save values of this new agent 572 $bindvars = Array(); 573 $query = 'update '.GALAXIA_TABLE_PREFIX.'agent_'.$agent['wf_agent_type'].' 574 set '; 575 //we wont need the old type anymore 576 unset($agent['wf_agent_type']); 577 $countfields = 0; 578 foreach ($agent as $key => $value) 579 { 580 if ($key) 581 { 582 $countfields++; 583 $query .= "$key = ? ,"; 584 $bindvars[] = $value; 585 } 586 } 587 $query = substr($query,'0',-1); 588 $query .= ' where wf_agent_id = ?'; 589 $bindvars[] = $agentid; 590 if ($countfields) $this->query($query, $bindvars); 591 } 592 } 593 } 594 } 595 //transitions 596 foreach($data['transitions'] as $tran) 597 { 598 $this->activity_manager->add_transition($pid,$actids[$tran['from']],$actids[$tran['to']]); 599 } 600 601 foreach ($data['jobs'] as $job) 602 { 603 $this->jobManager->replaceJob($pid, 0, $job); 604 } 605 606 // create a graph for the new process 607 $this->activity_manager->build_process_graph($pid); 608 //Test the final process 609 $this->activity_manager->validate_process_activities($pid); 610 611 $msg = sprintf(tra('Process %s %s imported'),$proc_info['wf_name'],$proc_info['wf_version']); 612 $this->notify_all(2,$msg); 613 $this->error[] = $msg; 614 return true; 615 } 616 617 /** 618 * Creates a new process based on an existing process changing the process version. 619 * By default the process is created as an unactive process and the version is by default a minor version of the process 620 * 621 * @param int $pId Process id 622 * @param bool $minor Process previous version 623 * @return int Process id 624 * @access public 625 */ 626 function new_process_version($pId, $minor=true) 627 { 628 if (!(isset($this->activity_manager))) $this->activity_manager = new ActivityManager($this->db); 629 $oldpid = $pId; 630 //retrieve process info with config rows 631 $proc_info = $this->get_process($pId, true); 632 if(!($proc_info) || (count($proc_info)==0)) return false; 633 $name = $proc_info['wf_name']; 634 635 // Now update the version 636 $version = $this->_new_version($proc_info['wf_version'],$minor); 637 while($this->getOne('select count(*) from '.GALAXIA_TABLE_PREFIX.'processes where wf_name=? and wf_version=?',array($name,$version))) 638 { 639 $version = $this->_new_version($version,$minor); 640 } 641 $oldname = $proc_info['wf_normalized_name']; 642 643 // Make new versions unactive 644 $proc_info['wf_version'] = $version; 645 $proc_info['wf_is_active'] = 'n'; 646 // create a new process, but don't create start/end activities 647 $pid = $this->replace_process(0, $proc_info, false); 648 if (!pid) return false; 649 650 //Since we are copying a process we should copy 651 //the old directory structure to the new directory 652 //oldname was saved a few lines before 653 $newname = $this->_get_normalized_name($pid); 654 $this->_rec_copy(GALAXIA_PROCESSES.SEP.$oldname.SEP.'code',GALAXIA_PROCESSES.SEP.$newname.SEP.'code'); 655 // And here copy all the activities & so 656 $query = 'select * from '.GALAXIA_TABLE_PREFIX.'activities where wf_p_id=?'; 657 $result = $this->query($query, array($oldpid)); 658 $newaid = array(); 659 while($res = $result->fetchRow()) { 660 $oldaid = $res['wf_activity_id']; 661 // the false tell the am not to create activities source files 662 $newaid[$oldaid] = $this->activity_manager->replace_activity($pid,0,$res, false); 663 } 664 // create transitions 665 $query = 'select * from '.GALAXIA_TABLE_PREFIX.'transitions where wf_p_id=?'; 666 $result = $this->query($query, array($oldpid)); 667 668 /* create the jobs */ 669 $query = "INSERT INTO " . GALAXIA_TABLE_PREFIX . "jobs (wf_process_id, name, description, time_start, interval_value, interval_unity, date_type, week_days, month_offset, active) (SELECT {$pid}, name, description, time_start, interval_value, interval_unity, date_type, week_days, month_offset, FALSE FROM " . GALAXIA_TABLE_PREFIX . "jobs WHERE wf_process_id = ?)"; 670 $this->query($query, array($oldpid)); 671 672 while($res = $result->fetchRow()) { 673 if (empty($newaid[$res['wf_act_from_id']]) || empty($newaid[$res['wf_act_to_id']])) { 674 continue; 675 } 676 $this->activity_manager->add_transition($pid,$newaid[$res['wf_act_from_id']],$newaid[$res['wf_act_to_id']]); 677 } 678 // create roles 679 if (!(isset($this->role_manager))) $this->role_manager = new RoleManager($this->db); 680 $query = 'select * from '.GALAXIA_TABLE_PREFIX.'roles where wf_p_id=?'; 681 $result = $this->query($query, array($oldpid)); 682 $newrid = array(); 683 while($res = $result->fetchRow()) { 684 if(!$this->role_manager->role_name_exists($pid,$res['wf_name'])) { 685 $rid=$this->role_manager->replace_role($pid,0,$res); 686 } else { 687 $rid = $this->role_manager->get_role_id($pid,$res['wf_name']); 688 } 689 $newrid[$res['wf_role_id']] = $rid; 690 } 691 // map users to roles 692 if (count($newrid) > 0) { 693 $query = 'select * from '.GALAXIA_TABLE_PREFIX.'user_roles where wf_p_id=?'; 694 $result = $this->query($query, array($oldpid)); 695 while($res = $result->fetchRow()) { 696 if (empty($newrid[$res['wf_role_id']])) { 697 continue; 698 } 699 $this->role_manager->map_user_to_role($pid,$res['wf_user'],$newrid[$res['wf_role_id']], $res['wf_account_type']); 700 } 701 } 702 // add roles to activities 703 if (count($newaid) > 0 && count($newrid ) > 0) { 704 $query = 'select * from '.GALAXIA_TABLE_PREFIX.'activity_roles where wf_activity_id in (' . join(', ',array_keys($newaid)) . ')'; 705 $result = $this->query($query); 706 while($res = $result->fetchRow()) { 707 if (empty($newaid[$res['wf_activity_id']]) || empty($newrid[$res['wf_role_id']])) { 708 continue; 709 } 710 $this->activity_manager->add_activity_role($newaid[$res['wf_activity_id']],$newrid[$res['wf_role_id']], $res['wf_readonly']); 711 } 712 } 713 714 //create agents 715 //get the list of agents used by the old process 716 $query = 'select gaa.* from '.GALAXIA_TABLE_PREFIX.'activity_agents gaa 717 INNER JOIN '.GALAXIA_TABLE_PREFIX.'activities gac ON gaa.wf_activity_id = gac.wf_activity_id 718 where gac.wf_p_id=?'; 719 $result = $this->query($query, array($oldpid)); 720 if (!(empty($result))) 721 { 722 while ($res = $result->fetchRow()) 723 { 724 //create a new agent of the same type for the new activity 725 $agentid = $this->activity_manager->add_activity_agent($newaid[$res['wf_activity_id']],$res['wf_agent_type']); 726 //save values of this new agents, taking the old ones, we make a simple copy 727 $old_activity_agent_data =& $this->activity_manager->get_activity_agent_data($res['wf_activity_id'],$res['wf_agent_type']); 728 //we wont need the old id and type 729 unset($old_activity_agent_data['wf_agent_id']); 730 unset($old_activity_agent_data['wf_agent_type']); 731 $bindvars = Array(); 732 $query = 'update '.GALAXIA_TABLE_PREFIX.'agent_'.$res['wf_agent_type'].' 733 set '; 734 $countfields = 0; 735 foreach ($old_activity_agent_data as $key => $value) 736 { 737 if ($key) 738 { 739 $countfields++; 740 $query .= "$key = ? ,"; 741 $bindvars[] = $value; 742 } 743 } 744 $query = substr($query,'0',-1); 745 $query .= ' where wf_agent_id = ?'; 746 $bindvars[] = $agentid; 747 if ($countfields) $this->query($query, $bindvars); 748 } 749 } 750 751 // create a graph for the new process 752 $this->activity_manager->build_process_graph($pid); 753 754 return $pid; 755 } 756 757 /** 758 * This function can be used to check if a process name exists, note that this is NOT used by replace_process since that function can be used to 759 * create new versions of an existing process. The application must use this method to ensure that processes have unique names. 760 * 761 * @param string $name Process name 762 * @param string $version Process version 763 * @return bool 764 * @access public 765 */ 766 function process_name_exists($name,$version) 767 { 768 $name = addslashes($this->_normalize_name($name,$version)); 769 return $this->getOne('select count(*) from '.GALAXIA_TABLE_PREFIX.'processes where wf_normalized_name=?',array($name)); 770 } 771 772 773 /** 774 * Gets a process by pId. Fields are returned as an associative array. 775 * If withConfig is set (false by default), the configuration options are returned as well the ['config'] key is then an array containing the config data with type distinction 776 * 777 * @param int $pId Process id 778 * @param bool $withConfig Configuration options 779 * @return bool 780 * @access public 781 */ 782 function get_process($pId, $withConfig=false) 783 { 784 $query = 'select * from '.GALAXIA_TABLE_PREFIX.'processes where wf_p_id=?'; 785 $result = $this->query($query, array($pId)); 786 if((empty($result)) || (!$result->numRows())) return false; 787 $res = $result->fetchRow(); 788 if ($withConfig) 789 { 790 // by setting true we force this function to keep type distinction on config values 791 $res['config'] = $this->getConfigValues($res['wf_p_id'], true); 792 } 793 return $res; 794 } 795 796 /** 797 * Lists all processes 798 * 799 * @param int $offset Resultset starting row 800 * @param int $maxRecords Max number of resulting rows 801 * @param string $sort_mode Sorting mode 802 * @param string $find Search query string 803 * @param string $where Condition query string 804 * @return bool 805 * @access public 806 */ 807 function list_processes($offset,$maxRecords,$sort_mode,$find='',$where='') 808 { 809 $sort_mode = $this->convert_sortmode($sort_mode); 810 if($find) { 811 $findesc = '%'.$find.'%'; 812 $mid=' where ((wf_name like ?) or (wf_description like ?))'; 813 $bindvars = array($findesc,$findesc); 814 } else { 815 $mid=''; 816 $bindvars = array(); 817 } 818 if($where) { 819 if($mid) { 820 $mid.= " and ($where) "; 821 } else { 822 $mid.= " where ($where) "; 823 } 824 } 825 $query = 'select * from '.GALAXIA_TABLE_PREFIX."processes $mid"; 826 $query_cant = 'select count(*) from '.GALAXIA_TABLE_PREFIX."processes $mid"; 827 $result = $this->query($query,$bindvars,$maxRecords,$offset, true, $sort_mode); 828 $cant = $this->getOne($query_cant,$bindvars); 829 $ret = Array(); 830 if (isset($result)) 831 { 832 while($res = $result->fetchRow()) 833 { 834 $ret[] = $res; 835 } 836 } 837 $retval = Array(); 838 $retval['data'] = $ret; 839 $retval['cant'] = $cant; 840 return $retval; 841 } 842 12 13 /** 14 * @var resource $parser xml parser 15 * @access public 16 */ 17 var $parser; 18 19 /** 20 * @var array $tree data struture 21 * @access public 22 */ 23 var $tree; 24 25 /** 26 * @var $current current element 27 * @access public 28 */ 29 var $current; 30 31 /** 32 * @var $buffer buffer for data 33 * @access public 34 */ 35 var $buffer; 36 37 /** 38 * @var object $Process Process 39 * @access public 40 */ 41 var $Process; 42 43 /** 44 * @var object $activity_manager Activity Manager 45 * @access public 46 */ 47 var $activity_manager; 48 49 /** 50 * @var object $jobManager Job Manager object 51 * @access public 52 */ 53 var $jobManager; 54 55 /** 56 * @var object $role_manager Role Manager 57 * @access public 58 */ 59 var $role_manager; 60 61 /** 62 * Constructor 63 * 64 * @param object &$db ADOdb 65 * @return object ProcessManager 66 * @access public 67 */ 68 function ProcessManager(&$db) 69 { 70 parent::BaseManager($db); 71 $this->child_name = 'ProcessManager'; 72 require_once(GALAXIA_LIBRARY.SEP.'src'.SEP.'ProcessManager'.SEP.'ActivityManager.php'); 73 require_once(GALAXIA_LIBRARY.SEP.'src'.SEP.'ProcessManager'.SEP.'JobManager.php'); 74 // $this->activity_manager is not set here to avoid objects loading object A loading object B loading object A, etc 75 //$this->role_manager will only be loaded when needed as well 76 } 77 78 /** 79 * Collect errors from all linked objects which could have been used by this object. 80 * Each child class should instantiate this function with her linked objetcs, calling get_error(true) 81 * 82 * @param bool $debug False by default, if true debug messages can be added to 'normal' messages 83 * @param string $prefix Appended to the debug message 84 * @return void 85 * @access public 86 */ 87 function collect_errors($debug=false, $prefix = '') 88 { 89 parent::collect_errors($debug, $prefix); 90 if (isset($this->activity_manager)) $this->error[] = $this->activity_manager->get_error(false, $debug, $prefix); 91 if (isset($this->role_manager)) $this->error[] = $this->role_manager->get_error(false, $debug, $prefix); 92 } 93 94 /** 95 * Activates a process 96 * 97 * @param int $pId Process id 98 * @return void 99 * @access public 100 */ 101 function activate_process($pId) 102 { 103 $query = 'update '.GALAXIA_TABLE_PREFIX.'processes set wf_is_active=? where wf_p_id=?'; 104 $this->query($query, array('y',$pId)); 105 $msg = sprintf(tra('Process %d has been activated'),$pId); 106 $this->error[] = $msg; 107 } 108 109 /** 110 * Deactivates a process 111 * 112 * @param int $pId Process id 113 * @return void 114 * @access public 115 */ 116 function deactivate_process($pId) 117 { 118 $query = 'update '.GALAXIA_TABLE_PREFIX.'processes set wf_is_active=? where wf_p_id=?'; 119 $this->query($query, array('n',$pId)); 120 $msg = sprintf(tra('Process %d has been deactivated'),$pId); 121 $this->error[] = $msg; 122 } 123 124 /** 125 * Creates an XML representation of a process 126 * 127 * @param int $pId Process id 128 * @return string 129 * @access public 130 */ 131 function serialize_process($pId) 132 { 133 if (!(isset($this->activity_manager))) $this->activity_manager = new ActivityManager($this->db); 134 // <process> 135 $out = '<process>'."\n"; 136 //we retrieve config values with the others process data 137 $proc_info =& $this->get_process($pId, true); 138 $wf_procname = $proc_info['wf_normalized_name']; 139 $out.= ' <name>'.htmlspecialchars($proc_info['wf_name']).'</name>'."\n"; 140 $out.= ' <isValid>'.htmlspecialchars($proc_info['wf_is_valid']).'</isValid>'."\n"; 141 $out.= ' <version>'.htmlspecialchars($proc_info['wf_version']).'</version>'."\n"; 142 $out.= ' <isActive>'.htmlspecialchars($proc_info['wf_is_active']).'</isActive>'."\n"; 143 $out.=' <description>'.htmlspecialchars($proc_info['wf_description']).'</description>'."\n"; 144 $out.= ' <lastModif>'.date("d/m/Y [h:i:s]",$proc_info['wf_last_modif']).'</lastModif>'."\n"; 145 146 //Shared code 147 $out.= ' <sharedCode><![CDATA['; 148 $fp=fopen(GALAXIA_PROCESSES.SEP."$wf_procname".SEP."code".SEP."shared.php","r"); 149 while(!feof($fp)) { 150 $line=fread($fp,8192); 151 $out.=$line; 152 } 153 fclose($fp); 154 $out.= ' ]]></sharedCode>'."\n"; 155 156 //Loop on config values 157 $out.=' <configs>'."\n"; 158 foreach($proc_info['config'] as $res) { 159 $name = $res['wf_config_name']; 160 $value_int = $res['wf_config_value_int']; 161 $value = $res['wf_config_value']; 162 $out.=' <config>'."\n"; 163 $out.=' <wf_config_name>'.htmlspecialchars($name).'</wf_config_name>'."\n"; 164 $out.=' <wf_config_value>'.htmlspecialchars($value).'</wf_config_value>'."\n"; 165 $out.=' <wf_config_value_int>'.htmlspecialchars($value_int).'</wf_config_value_int>'."\n"; 166 $out.=' </config>'."\n"; 167 } 168 $out.=' </configs>'."\n"; 169 170 // Now loop over activities 171 $query = "select * from ".GALAXIA_TABLE_PREFIX."activities where wf_p_id=$pId"; 172 $result = $this->query($query); 173 $out.=' <activities>'."\n"; 174 while($res = $result->fetchRow()) { 175 $name = $res['wf_normalized_name']; 176 $out.=' <activity>'."\n"; 177 $out.=' <name>'.htmlspecialchars($res['wf_name']).'</name>'."\n"; 178 $out.=' <type>'.htmlspecialchars($res['wf_type']).'</type>'."\n"; 179 $out.=' <description>'.htmlspecialchars($res['wf_description']).'</description>'."\n"; 180 $out.=' <lastModif>'.date("d/m/Y [h:i:s]",$res['wf_last_modif']).'</lastModif>'."\n"; 181 $out.=' <isInteractive>'.$res['wf_is_interactive'].'</isInteractive>'."\n"; 182 $out.=' <isAutoRouted>'.$res['wf_is_autorouted'].'</isAutoRouted>'."\n"; 183 $out.=' <roles>'."\n"; 184 //loop on activity roles 185 $actid = $res['wf_activity_id']; 186 $roles =& $this->activity_manager->get_activity_roles($actid); 187 foreach($roles as $role) { 188 if ($role['wf_readonly']) 189 { 190 $out.=' <role readonly="true">'.htmlspecialchars($role['wf_name']).'</role>'."\n"; 191 } 192 else 193 { 194 $out.=' <role>'.htmlspecialchars($role['wf_name']).'</role>'."\n"; 195 } 196 } 197 $out.=' </roles>'."\n"; 198 $out.=' <agents>'."\n"; 199 //loop on activity agents 200 $agents =& $this->activity_manager->get_activity_agents($actid); 201 foreach($agents as $agent) { 202 $out.=' <agent>'."\n"; 203 $out.=' <agent_type>'.htmlspecialchars($agent['wf_agent_type']).'</agent_type>'."\n"; 204 //loop on agent datas 205 $agent_data =& $this->activity_manager->get_activity_agent_data($actid,$agent['wf_agent_type']); 206 $out.=' <agent_datas>'."\n"; 207 foreach($agent_data as $key => $value) 208 { 209 if (!($key=='wf_agent_id')) 210 { 211 $out.=' <agent_data>'."\n"; 212 $out.=' <name>'.htmlspecialchars($key).'</name>'."\n"; 213 $out.=' <value>'.htmlspecialchars($value).'</value>'."\n"; 214 $out.=' </agent_data>'."\n"; 215 } 216 } 217 $out.=' </agent_datas>'."\n"; 218 $out.=' </agent>'."\n"; 219 } 220 $out.=' </agents>'."\n"; 221 222 //the code 223 $out.=' <code><![CDATA['; 224 $fp=fopen(GALAXIA_PROCESSES.SEP."$wf_procname".SEP."code".SEP."activities".SEP."$name.php","r"); 225 while(!feof($fp)) { 226 $line=fread($fp,8192); 227 $out.=$line; 228 } 229 fclose($fp); 230 $out.=' ]]></code>'; 231 if($res['wf_is_interactive']=='y') { 232 $out.=' <template><![CDATA['; 233 $fp=fopen(GALAXIA_PROCESSES.SEP."$wf_procname".SEP."code".SEP."templates".SEP."$name.tpl","r"); 234 while(!feof($fp)) { 235 $line=fread($fp,8192); 236 $out.=$line; 237 } 238 fclose($fp); 239 $out.=' ]]></template>'; 240 } 241 $out.=' </activity>'."\n"; 242 } 243 $out.=' </activities>'."\n"; 244 $out.=' <transitions>'."\n"; 245 //loop on transitions 246 $transitions = $this->activity_manager->get_process_transitions($pId); 247 foreach($transitions as $tran) { 248 $out.=' <transition>'."\n"; 249 $out.=' <from>'.htmlspecialchars($tran['wf_act_from_name']).'</from>'."\n"; 250 $out.=' <to>'.htmlspecialchars($tran['wf_act_to_name']).'</to>'."\n"; 251 $out.=' </transition>'."\n"; 252 } 253 $out.=' </transitions>'."\n"; 254 $out.= '</process>'."\n"; 255 //$fp = fopen(GALAXIA_PROCESSES."/$wf_procname/$wf_procname.xml","w"); 256 //fwrite($fp,$out); 257 //fclose($fp); 258 return $out; 259 } 260 261 /** 262 * Creates a process PHP data structure from its XML representation 263 * 264 * @param string &$xml XML document 265 * @return array Process data structure 266 * @access public 267 */ 268 function unserialize_process(&$xml) 269 { 270 // Create SAX parser assign this object as base for handlers 271 // handlers are private methods defined below. 272 // keep contexts and parse 273 $this->parser = xml_parser_create(); 274 xml_parser_set_option($this->parser,XML_OPTION_CASE_FOLDING,0); 275 //xml_parser_set_option($parser,XML_OPTION_SKIP_WHITE, 1); 276 xml_set_object($this->parser, $this); 277 xml_set_element_handler($this->parser, '_start_element_handler', '_end_element_handler'); 278 xml_set_character_data_handler($this->parser, '_data_handler'); 279 $aux=Array( 280 'name'=>'root', 281 'children'=>Array(), 282 'parent' => 0, 283 'data'=>'', 284 'attribs' => Array(), 285 ); 286 $this->tree[0]=$aux; 287 $this->current=0; 288 289 290 if (!xml_parse($this->parser, $xml, true)) { 291 $error = sprintf("XML error: %s at line %d", 292 xml_error_string(xml_get_error_code($this->parser)), 293 xml_get_current_line_number($this->parser)); 294 trigger_error($error,E_USER_WARNING); 295 $this->error[] = $error; 296 } 297 xml_parser_free($this->parser); 298 // Now that we have the tree we can do interesting things 299 300 $process=Array(); 301 $activities=Array(); 302 $transitions=Array(); 303 for($i=0;$i<count($this->tree[1]['children']);$i++) { 304 // Process attributes 305 $z=$this->tree[1]['children'][$i]; 306 $name = trim($this->tree[$z]['name']); 307 308 //config values 309 if ($name=='configs') { 310 for($j=0;$j<count($this->tree[$z]['children']);$j++) { 311 $z2 = $this->tree[$z]['children'][$j]; 312 // this is a config $name = $this->tree[$z2]['name']; 313 $aux = Array(); 314 if($this->tree[$z2]['name']=='config') { 315 for($k=0;$k<count($this->tree[$z2]['children']);$k++) { 316 $z3 = $this->tree[$z2]['children'][$k]; 317 $name = trim($this->tree[$z3]['name']); 318 $value= trim($this->tree[$z3]['data']); 319 $aux[$name]=$value; 320 } 321 $configs[]=$aux; 322 } 323 } 324 } 325 //activities 326 elseif($name=='activities') { 327 for($j=0;$j<count($this->tree[$z]['children']);$j++) { 328 $z2 = $this->tree[$z]['children'][$j]; 329 // this is an activity $name = $this->tree[$z2]['name']; 330 $aux = Array(); 331 if($this->tree[$z2]['name']=='activity') { 332 for($k=0;$k<count($this->tree[$z2]['children']);$k++) { 333 $z3 = $this->curre[$z2]['children'][$k]; 334 $name = trim($this->tree[$z3]['name']); 335 $value= trim($this->tree[$z3]['data']); 336 if($name=='roles') { 337 $roles=Array(); 338 for($l=0;$l<count($this->tree[$z3]['children']);$l++) { 339 $z4 = $this->tree[$z3]['children'][$l]; 340 $name = trim($this->tree[$z4]['name']); 341 $data = trim($this->tree[$z4]['data']); 342 $attribs = $this->tree[$z4]['attribs']; 343 $readonly = false; 344 if ( (isset($attribs['readonly'])) && ($attribs['readonly'])) 345 { 346 //role in read-only 347 $readonly = true; 348 } 349 $roles[]=array( 350 'name' => $data, 351 'readonly' => $readonly, 352 ); 353 } 354 } 355 elseif ($name=='agents') 356 { 357 $agents=Array(); 358 for($l=0;$l<count($this->tree[$z3]['children']);$l++) 359 { 360 $z4 = $this->tree[$z3]['children'][$l]; 361 //$name is agent 362 $name = trim($this->tree[$z4]['name']); 363 if ($name = 'agent') 364 { 365 $agent = array(); 366 for($m=0;$m<count($this->tree[$z4]['children']);$m++) 367 { 368 $z5 = $this->tree[$z4]['children'][$m]; 369 //$name is agent_type or agent_datas 370 $name = trim($this->tree[$z5]['name']); 371 // data will be the agent_type or an array for agent_datas 372 $data = trim($this->tree[$z5]['data']); 373 if ($name=='agent_type') 374 { 375 $agent['wf_agent_type']=$data; 376 } 377 elseif ($name=='agent_datas') 378 { 379 for($n=0;$n<count($this->tree[$z5]['children']);$n++) 380 { 381 $z6 = $this->tree[$z5]['children'][$n]; 382 //$name is agent_data $val is an array 383 $name = trim($this->tree[$z6]['name']); 384 $val = trim($this->tree[$z6]['data']); 385 if ($name=='agent_data') 386 { 387 for($o=0;$o<count($this->tree[$z6]['children']);$o++) 388 { 389 $z7 = $this->tree[$z6]['children'][$o]; 390 //$name is agent_data $val is 'name' or 'value' 391 $name = trim($this->tree[$z7]['name']); 392 $content = trim($this->tree[$z7]['data']); 393 //echo "<br>z7 name $name content: $content"; 394 if ($name=='name') 395 { 396 $agent_data_name = $content; 397 } 398 elseif ($name=='value') 399 { 400 $agent_data_value =& $content; 401 } 402 } 403 //echo "<br>associate $agent_data_name to $agent_data_value <hr>"; 404 $agent[$agent_data_name] = $agent_data_value; 405 } 406 } 407 } 408 } 409 $agents[]=$agent; 410 } 411 } 412 } else { 413 $aux[$name]=$value; 414 //print("$name:$value<br/>"); 415 } 416 } 417 $aux['agents']=$agents; 418 $aux['roles']=$roles; 419 $activities[]=$aux; 420 } 421 } 422 } elseif($name=='transitions') { 423 for($j=0;$j<count($this->tree[$z]['children']);$j++) { 424 $z2 = $this->tree[$z]['children'][$j]; 425 // this is an activity $name = $this->tree[$z2]['name']; 426 $aux=Array(); 427 if($this->tree[$z2]['name']=='transition') { 428 for($k=0;$k<count($this->tree[$z2]['children']);$k++) { 429 $z3 = $this->tree[$z2]['children'][$k]; 430 $name = trim($this->tree[$z3]['name']); 431 $value= trim($this->tree[$z3]['data']); 432 if($name == 'from' || $name == 'to') { 433 $aux[$name]=$value; 434 } 435 } 436 } 437 $transitions[] = $aux; 438 } 439 } else { 440 $value = trim($this->tree[$z]['data']); 441 //print("$name is $value<br/>"); 442 $process[$name]=$value; 443 } 444 } 445 $process['configs']=$configs; 446 $process['activities']=$activities; 447 $process['transitions']=$transitions; 448 return $process; 449 } 450 451 /** 452 * Creates a process from the process data structure, if you want to convert an XML to a process then use first unserialize_process and then this method. 453 * 454 * @access public 455 * @param string &$data 456 * @return bool 457 */ 458 function import_process(&$data) 459 { 460 //Now the show begins 461 if (!(isset($this->activity_manager))) $this->activity_manager = new ActivityManager($this->db); 462 if (!(isset($this->role_manager))) $this->role_manager = new RoleManager($this->db); 463 if (!isset($this->jobManager)) 464 $this->jobManager = new JobManager($this->db); 465 466 // First create the process. Always inactive and inactive first. 467 $vars = Array( 468 'wf_name' => trim($data['name']), 469 'wf_version' => $data['version'], 470 'wf_description' => $data['description'], 471 'wf_last_modif' => $data['lastModif'], 472 'wf_is_active' => false, 473 'wf_is_valid' => false, 474 'config' => $data['configs'], 475 ); 476 477 if (empty($vars['wf_name'])) 478 { 479 $msg = tra('invalid name specified'); 480 $this->error[] = $msg; 481 return false; 482 } 483 484 if (ereg('^[0-9]{1,2}\.[0-9]{1,2}$', $vars['wf_version']) === false) 485 { 486 $msg = tra('invalid version specified'); 487 $this->error[] = $msg; 488 return false; 489 } 490 491 if ($this->process_name_exists($vars['wf_name'], $vars['wf_version'])) 492 { 493 $msg = sprintf(tra('Process %s %s already exists, the import process was aborted'),$vars['wf_name'],$vars['wf_version']); 494 $this->error[] = $msg; 495 return false; 496 } 497 $pid = $this->replace_process(0,$vars,false); 498 //Put the shared code 499 $proc_info = $this->get_process($pid); 500 $wf_procname = $proc_info['wf_normalized_name']; 501 $fp = fopen(GALAXIA_PROCESSES.SEP.$wf_procname.SEP.'code'.SEP.'shared.php',"w"); 502 fwrite($fp, $data['sharedCode']); 503 fclose($fp); 504 $actids = Array(); 505 506 // Foreach activity create activities 507 foreach($data['activities'] as $activity) { 508 509 $vars = Array( 510 'wf_name' => $activity['name'], 511 'wf_description' => $activity['description'], 512 'wf_type' => $activity['type'], 513 'wf_menu_path' => $activity['menuPath'], 514 'wf_last_modif' => $activity['lastModif'], 515 'wf_is_interactive' => $activity['isInteractive'], 516 'wf_is_autorouted' => $activity['isAutoRouted'] 517 ); 518 $actname=$this->activity_manager->_normalize_name($activity['name']); 519 $actid = $this->activity_manager->replace_activity($pid,0,$vars); 520 521 $fp = fopen(GALAXIA_PROCESSES.SEP.$wf_procname.SEP.'code'.SEP.'activities'.SEP.$actname.'.php',"w"); 522 fwrite($fp, $activity['code']); 523 fclose($fp); 524 if($activity['isInteractive']=='y') { 525 $fp = fopen(GALAXIA_PROCESSES.SEP.$wf_procname.SEP.'code'.SEP.'templates'.SEP.$actname.'.tpl',"w"); 526 fwrite($fp,$activity['template']); 527 fclose($fp); 528 } 529 $actids[$activity['name']] = $this->activity_manager->_get_activity_id_by_name($pid, $activity['name']); 530 $actname = $this->activity_manager->_normalize_name($activity['name']); 531 $now = date("U"); 532 //roles 533 if( is_array($activity['roles']) && count($activity['roles']) > 0 ) 534 { 535 foreach($activity['roles'] as $role) 536 { 537 $rolename = $role['name']; 538 $vars = Array( 539 'wf_name' => $rolename, 540 'wf_description' => $rolename, 541 'wf_last_modif' => $now, 542 ); 543 if(!$this->role_manager->role_name_exists($pid,$rolename)) { 544 $rid=$this->role_manager->replace_role($pid,0,$vars); 545 } else { 546 $rid = $this->role_manager->get_role_id($pid,$rolename); 547 } 548 if($actid && $rid) { 549 $this->activity_manager->add_activity_role($actid,$rid,$role['readonly']); 550 } 551 } 552 } 553 //agents 554 if( is_array($activity['agents']) && count($activity['agents']) > 0 ) 555 { 556 foreach($activity['agents'] as $agent) 557 { 558 if (empty($agent['wf_agent_type'])) 559 { 560 $this->error[] = lang('empty agent type'); 561 } 562 else 563 { 564 //create a new agent of the same type for the new activity 565 $agentid = $this->activity_manager->add_activity_agent($actid,$agent['wf_agent_type']); 566 //save values of this new agent 567 $bindvars = Array(); 568 $query = 'update '.GALAXIA_TABLE_PREFIX.'agent_'.$agent['wf_agent_type'].' 569 set '; 570 //we wont need the old type anymore 571 unset($agent['wf_agent_type']); 572 $countfields = 0; 573 foreach ($agent as $key => $value) 574 { 575 if ($key) 576 { 577 $countfields++; 578 $query .= "$key = ? ,"; 579 $bindvars[] = $value; 580 } 581 } 582 $query = substr($query,'0',-1); 583 $query .= ' where wf_agent_id = ?'; 584 $bindvars[] = $agentid; 585 if ($countfields) $this->query($query, $bindvars); 586 } 587 } 588 } 589 } 590 //transitions 591 foreach($data['transitions'] as $tran) 592 { 593 $this->activity_manager->add_transition($pid,$actids[$tran['from']],$actids[$tran['to']]); 594 } 595 596 foreach ($data['jobs'] as $job) 597 { 598 $this->jobManager->replaceJob($pid, 0, $job); 599 } 600 601 // create a graph for the new process 602 $this->activity_manager->build_process_graph($pid); 603 //Test the final process 604 $this->activity_manager->validate_process_activities($pid); 605 606 $msg = sprintf(tra('Process %s %s imported'),$proc_info['wf_name'],$proc_info['wf_version']); 607 $this->error[] = $msg; 608 return true; 609 } 610 611 /** 612 * Creates a new process based on an existing process changing the process version. 613 * By default the process is created as an unactive process and the version is by default a minor version of the process 614 * 615 * @param int $pId Process id 616 * @param bool $minor Process previous version 617 * @return int Process id 618 * @access public 619 */ 620 function new_process_version($pId, $minor=true) 621 { 622 if (!(isset($this->activity_manager))) $this->activity_manager = new ActivityManager($this->db); 623 $oldpid = $pId; 624 //retrieve process info with config rows 625 $proc_info = $this->get_process($pId, true); 626 if(!($proc_info) || (count($proc_info)==0)) return false; 627 $name = $proc_info['wf_name']; 628 629 // Now update the version 630 $version = $this->_new_version($proc_info['wf_version'],$minor); 631 while($this->getOne('select count(*) from '.GALAXIA_TABLE_PREFIX.'processes where wf_name=? and wf_version=?',array($name,$version))) 632 { 633 $version = $this->_new_version($version,$minor); 634 } 635 $oldname = $proc_info['wf_normalized_name']; 636 637 // Make new versions unactive 638 $proc_info['wf_version'] = $version; 639 $proc_info['wf_is_active'] = 'n'; 640 // create a new process, but don't create start/end activities 641 $pid = $this->replace_process(0, $proc_info, false); 642 if (!pid) return false; 643 644 //Since we are copying a process we should copy 645 //the old directory structure to the new directory 646 //oldname was saved a few lines before 647 $newname = $this->_get_normalized_name($pid); 648 $this->_rec_copy(GALAXIA_PROCESSES.SEP.$oldname.SEP.'code',GALAXIA_PROCESSES.SEP.$newname.SEP.'code'); 649 // And here copy all the activities & so 650 $query = 'select * from '.GALAXIA_TABLE_PREFIX.'activities where wf_p_id=?'; 651 $result = $this->query($query, array($oldpid)); 652 $newaid = array(); 653 while($res = $result->fetchRow()) { 654 $oldaid = $res['wf_activity_id']; 655 // the false tell the am not to create activities source files 656 $newaid[$oldaid] = $this->activity_manager->replace_activity($pid,0,$res, false); 657 } 658 // create transitions 659 $query = 'select * from '.GALAXIA_TABLE_PREFIX.'transitions where wf_p_id=?'; 660 $result = $this->query($query, array($oldpid)); 661 662 /* create the jobs */ 663 $query = "INSERT INTO " . GALAXIA_TABLE_PREFIX . "jobs (wf_process_id, name, description, time_start, interval_value, interval_unity, date_type, week_days, month_offset, active) (SELECT {$pid}, name, description, time_start, interval_value, interval_unity, date_type, week_days, month_offset, FALSE FROM " . GALAXIA_TABLE_PREFIX . "jobs WHERE wf_process_id = ?)"; 664 $this->query($query, array($oldpid)); 665 666 while($res = $result->fetchRow()) { 667 if (empty($newaid[$res['wf_act_from_id']]) || empty($newaid[$res['wf_act_to_id']])) { 668 continue; 669 } 670 $this->activity_manager->add_transition($pid,$newaid[$res['wf_act_from_id']],$newaid[$res['wf_act_to_id']]); 671 } 672 // create roles 673 if (!(isset($this->role_manager))) $this->role_manager = new RoleManager($this->db); 674 $query = 'select * from '.GALAXIA_TABLE_PREFIX.'roles where wf_p_id=?'; 675 $result = $this->query($query, array($oldpid)); 676 $newrid = array(); 677 while($res = $result->fetchRow()) { 678 if(!$this->role_manager->role_name_exists($pid,$res['wf_name'])) { 679 $rid=$this->role_manager->replace_role($pid,0,$res); 680 } else { 681 $rid = $this->role_manager->get_role_id($pid,$res['wf_name']); 682 } 683 $newrid[$res['wf_role_id']] = $rid; 684 } 685 // map users to roles 686 if (count($newrid) > 0) { 687 $query = 'select * from '.GALAXIA_TABLE_PREFIX.'user_roles where wf_p_id=?'; 688 $result = $this->query($query, array($oldpid)); 689 while($res = $result->fetchRow()) { 690 if (empty($newrid[$res['wf_role_id']])) { 691 continue; 692 } 693 $this->role_manager->map_user_to_role($pid,$res['wf_user'],$newrid[$res['wf_role_id']], $res['wf_account_type']); 694 } 695 } 696 // add roles to activities 697 if (count($newaid) > 0 && count($newrid ) > 0) { 698 $query = 'select * from '.GALAXIA_TABLE_PREFIX.'activity_roles where wf_activity_id in (' . join(', ',array_keys($newaid)) . ')'; 699 $result = $this->query($query); 700 while($res = $result->fetchRow()) { 701 if (empty($newaid[$res['wf_activity_id']]) || empty($newrid[$res['wf_role_id']])) { 702 continue; 703 } 704 $this->activity_manager->add_activity_role($newaid[$res['wf_activity_id']],$newrid[$res['wf_role_id']], $res['wf_readonly']); 705 } 706 } 707 708 //create agents 709 //get the list of agents used by the old process 710 $query = 'select gaa.* from '.GALAXIA_TABLE_PREFIX.'activity_agents gaa 711 INNER JOIN '.GALAXIA_TABLE_PREFIX.'activities gac ON gaa.wf_activity_id = gac.wf_activity_id 712 where gac.wf_p_id=?'; 713 $result = $this->query($query, array($oldpid)); 714 if (!(empty($result))) 715 { 716 while ($res = $result->fetchRow()) 717 { 718 //create a new agent of the same type for the new activity 719 $agentid = $this->activity_manager->add_activity_agent($newaid[$res['wf_activity_id']],$res['wf_agent_type']); 720 //save values of this new agents, taking the old ones, we make a simple copy 721 $old_activity_agent_data =& $this->activity_manager->get_activity_agent_data($res['wf_activity_id'],$res['wf_agent_type']); 722 //we wont need the old id and type 723 unset($old_activity_agent_data['wf_agent_id']); 724 unset($old_activity_agent_data['wf_agent_type']); 725 $bindvars = Array(); 726 $query = 'update '.GALAXIA_TABLE_PREFIX.'agent_'.$res['wf_agent_type'].' 727 set '; 728 $countfields = 0; 729 foreach ($old_activity_agent_data as $key => $value) 730 { 731 if ($key) 732 { 733 $countfields++; 734 $query .= "$key = ? ,"; 735 $bindvars[] = $value; 736 } 737 } 738 $query = substr($query,'0',-1); 739 $query .= ' where wf_agent_id = ?'; 740 $bindvars[] = $agentid; 741 if ($countfields) $this->query($query, $bindvars); 742 } 743 } 744 745 // create a graph for the new process 746 $this->activity_manager->build_process_graph($pid); 747 748 return $pid; 749 } 750 751 /** 752 * This function can be used to check if a process name exists, note that this is NOT used by replace_process since that function can be used to 753 * create new versions of an existing process. The application must use this method to ensure that processes have unique names. 754 * 755 * @param string $name Process name 756 * @param string $version Process version 757 * @return bool 758 * @access public 759 */ 760 function process_name_exists($name,$version) 761 { 762 $name = addslashes($this->_normalize_name($name,$version)); 763 return $this->getOne('select count(*) from '.GALAXIA_TABLE_PREFIX.'processes where wf_normalized_name=?',array($name)); 764 } 765 766 767 /** 768 * Gets a process by pId. Fields are returned as an associative array. 769 * If withConfig is set (false by default), the configuration options are returned as well the ['config'] key is then an array containing the config data with type distinction 770 * 771 * @param int $pId Process id 772 * @param bool $withConfig Configuration options 773 * @return bool 774 * @access public 775 */ 776 function get_process($pId, $withConfig=false) 777 { 778 $query = 'select * from '.GALAXIA_TABLE_PREFIX.'processes where wf_p_id=?'; 779 $result = $this->query($query, array($pId)); 780 if((empty($result)) || (!$result->numRows())) return false; 781 $res = $result->fetchRow(); 782 if ($withConfig) 783 { 784 // by setting true we force this function to keep type distinction on config values 785 $res['config'] = $this->getConfigValues($res['wf_p_id'], true); 786 } 787 return $res; 788 } 789 790 /** 791 * Lists all processes 792 * 793 * @param int $offset Resultset starting row 794 * @param int $maxRecords Max number of resulting rows 795 * @param string $sort_mode Sorting mode 796 * @param string $find Search query string 797 * @param string $where Condition query string 798 * @return bool 799 * @access public 800 */ 801 function list_processes($offset,$maxRecords,$sort_mode,$find='',$where='') 802 { 803 $sort_mode = $this->convert_sortmode($sort_mode); 804 if($find) { 805 $findesc = '%'.$find.'%'; 806 $mid=' where ((wf_name like ?) or (wf_description like ?))'; 807 $bindvars = array($findesc,$findesc); 808 } else { 809 $mid=''; 810 $bindvars = array(); 811 } 812 if($where) { 813 if($mid) { 814 $mid.= " and ($where) "; 815 } else { 816 $mid.= " where ($where) "; 817 } 818 } 819 $query = 'select * from '.GALAXIA_TABLE_PREFIX."processes $mid"; 820 $query_cant = 'select count(*) from '.GALAXIA_TABLE_PREFIX."processes $mid"; 821 $result = $this->query($query,$bindvars,$maxRecords,$offset, true, $sort_mode); 822 $cant = $this->getOne($query_cant,$bindvars); 823 $ret = Array(); 824 if (isset($result)) 825 { 826 while($res = $result->fetchRow()) 827 { 828 $ret[] = $res; 829 } 830 } 831 $retval = Array(); 832 $retval['data'] = $ret; 833 $retval['cant'] = $cant; 834 return $retval; 835 } 836 843 837 /*! 844 838 Marks a process as an invalid process 845 */846 function invalidate_process($pid)847 {848 $query = 'update '.GALAXIA_TABLE_PREFIX.'processes set wf_is_valid=? where wf_p_id=?';849 $this->query($query, array('n',$pid));850 }851 852 /**853 * Removes a process by pId854 *855 * @param int $pId Process id856 * @return bool857 * @access public858 839 */ 859 function remove_process($pId) 860 { 861 if (!(isset($this->activity_manager))) $this->activity_manager = new ActivityManager($this->db); 862 if (!isset($this->jobManager)) 863 $this->jobManager = new JobManager($this->db); 864 $this->deactivate_process($pId); 865 $name = $this->_get_normalized_name($pId); 866 867 // start a transaction 868 $this->db->StartTrans(); 869 $this->jobManager->removeJobsByProcessID($pId); 870 871 // Remove process activities 872 $query = 'select wf_activity_id from '.GALAXIA_TABLE_PREFIX.'activities where wf_p_id=?'; 873 $result = $this->query($query, array($pId)); 874 while($res = $result->fetchRow()) { 875 //we add a false parameter to prevent the ActivityManager from opening a new transaction 876 $this->activity_manager->remove_activity($pId,$res['wf_activity_id'], false); 877 } 878 879 // Remove process roles 880 $query = 'delete from '.GALAXIA_TABLE_PREFIX.'roles where wf_p_id=?'; 881 $this->query($query, array($pId)); 882 $query = 'delete from '.GALAXIA_TABLE_PREFIX.'user_roles where wf_p_id=?'; 883 $this->query($query, array($pId)); 884 885 // Remove process instances 886 $query = 'delete from '.GALAXIA_TABLE_PREFIX.'instances where wf_p_id=?'; 887 $this->query($query, array($pId)); 888 889 // Remove the directory structure 890 if (!empty($name) && is_dir(GALAXIA_PROCESSES.SEP.$name)) { 891 $this->_remove_directory(GALAXIA_PROCESSES.SEP.$name,true); 892 } 893 if (GALAXIA_TEMPLATES && !empty($name) && is_dir(GALAXIA_TEMPLATES.SEP.$name)) { 894 $this->_remove_directory(GALAXIA_TEMPLATES.SEP.$name,true); 895 } 896 897 // Remove configuration data 898 $query = 'delete from '.GALAXIA_TABLE_PREFIX.'process_config where wf_p_id=?'; 899 $this->query($query, array($pId)); 900 901 // And finally remove the proc 902 $query = 'delete from '.GALAXIA_TABLE_PREFIX.'processes where wf_p_id=?'; 903 $this->query($query, array($pId)); 904 $msg = sprintf(tra('Process %s removed'),$name); 905 $this->notify_all(5,$msg); 906 $this->error[] = $msg; 907 908 // perform commit (return true) or Rollback (return false) 909 return $this->db->CompleteTrans(); 910 911 } 912 913 /** 914 * Updates or inserts a new process in the database, $vars is an associative array containing the fields to update or to insert as needed. 915 * Configuration options should be in an array associated with the 'config' key 916 * this config array should contain 'wf_config_name', 'wf_config_value' and 'wf_config_value_int' keys. 917 * $pId is the processI. If $pId is 0 then we create a new process, else we are in edit mode. 918 * if $create is true start and end activities will be created (when importing use $create=false) 919 * 920 * @param int $pId Process id, if 0 then we create a new process, else we are in edit mode 921 * @param array &$vars Associative containing the fields to update or to insert as needed 922 * @param bool $create If true, start and end activities will be created (when importing use $create=false). 923 * @return int Process id 924 * @access public 925 */ 926 function replace_process($pId, &$vars, $create = true) 927 { 928 if (!(isset($this->activity_manager))) $this->activity_manager = new ActivityManager($this->db); 929 $TABLE_NAME = GALAXIA_TABLE_PREFIX.'processes'; 930 $now = date("U"); 931 $vars['wf_last_modif']=$now; 932 $vars['wf_normalized_name'] = $this->_normalize_name($vars['wf_name'],$vars['wf_version']); 933 $config_array = array(); 934 935 foreach($vars as $key=>$value) 936 { 937 if ($key=='config') 938 { 939 $config_array_init =& $value; 940 // rebuild a nice config_array with type of config and value 941 if( is_array($config_array_init) && count($config_array_init) > 0 ) 942 { 943 foreach($config_array_init as $config) 944 { 945 if (isset($config['wf_config_value_int']) && (!($config['wf_config_value_int']==''))) 946 { 947 $config_array[$config['wf_config_name']] = array('int' => $config['wf_config_value_int']); 948 } 949 else 950 { 951 if (isset($config['wf_config_value'])) 952 { 953 $config_array[$config['wf_config_name']] = array('text' => $config['wf_config_value']); 954 } 955 } 956 } 957 } 958 //no need to keep it in the vars array, this array is used in queries 959 unset($vars['config']); 960 } 961 else // not config, it's just process's fields values 962 { 963 $vars[$key]=addslashes($value); 964 } 965 } 966 967 if($pId) { 968 // update mode 969 $old_proc = $this->get_process($pId); 970 $first = true; 971 $query ="update $TABLE_NAME set"; 972 foreach($vars as $key=>$value) { 973 if(!$first) $query.= ','; 974 if(!is_numeric($value)||strstr($value,'.')) $value="'".$value."'"; 975 $query.= " $key=$value "; 976 $first = false; 977 } 978 $query .= " where wf_p_id=$pId "; 979 $this->query($query); 980 981 //set config values 982 $this->setConfigValues($pId,$config_array); 983 984 // Note that if the name is being changed then 985 // the directory has to be renamed! 986 $oldname = $old_proc['wf_normalized_name']; 987 $newname = $vars['wf_normalized_name']; 988 if ($newname != $oldname) { 989 rename(GALAXIA_PROCESSES.SEP."$oldname",GALAXIA_PROCESSES.SEP."$newname"); 990 } 991 $msg = sprintf(tra('Process %s has been updated'),$vars['wf_name']); 992 $this->notify_all(3,$msg); 993 $this->error[] = $msg; 994 } else { 995 unset($vars['wf_p_id']); 996 // insert mode 997 $name = $this->_normalize_name($vars['wf_name'],$vars['wf_version']); 998 $this->_create_directory_structure($name); 999 $first = true; 1000 $query = "insert into $TABLE_NAME("; 1001 foreach(array_keys($vars) as $key) { 1002 if(!$first) $query.= ','; 1003 $query.= "$key"; 1004 $first = false; 1005 } 1006 $query .=") values("; 1007 $first = true; 1008 foreach(array_values($vars) as $value) { 1009 if(!$first) $query.= ','; 1010 if(!is_numeric($value)||strstr($value,'.')) $value="'".$value."'"; 1011 $query.= "$value"; 1012 $first = false; 1013 } 1014 $query .=")"; 1015 $this->query($query); 1016 //FIXME: this query seems to be quite sure to get a result, I would prefer something 1017 // more sure to get the right result everytime 1018 $pId = $this->getOne("select max(wf_p_id) from $TABLE_NAME where wf_last_modif=$now"); 1019 1020 //set config values 1021 $this->setConfigValues($pId,$config_array); 1022 1023 // Now automatically add a start and end activity 1024 // unless importing ($create = false) 1025 if($create) { 1026 $vars1 = Array( 1027 'wf_name' => 'start', 1028 'wf_description' => 'default start activity', 1029 'wf_type' => 'start', 1030 'wf_is_interactive' => 'y', 1031 'wf_is_autorouted' => 'y' 1032 ); 1033 $vars2 = Array( 1034 'wf_name' => 'end', 1035 'wf_description' => 'default end activity', 1036 'wf_type' => 'end', 1037 'wf_is_interactive' => 'n', 1038 'wf_is_autorouted' => 'y' 1039 ); 1040 1041 $this->activity_manager->replace_activity($pId,0,$vars1); 1042 $this->activity_manager->replace_activity($pId,0,$vars2); 1043 } 1044 $msg = sprintf(tra('Process %s has been created'),$vars['wf_name']); 1045 $this->notify_all(4,$msg); 1046 $this->error[] = $msg; 1047 } 1048 // Get the id 1049 return $pId; 1050 } 1051 1052 /** 1053 * Gets the normalized name of a process by pid 1054 * 1055 * @param int $pId Process id 1056 * @access private 1057 * @return string 1058 */ 1059 function _get_normalized_name($pId) 1060 { 1061 $info = $this->get_process($pId); 1062 return $info['wf_normalized_name']; 1063 } 1064 1065 /** 1066 * Normalizes a process name 1067 * 1068 * @param string $name Process name to be normalized 1069 * @param string $version Process version 1070 * @access private 1071 * @return string Process normalized name 1072 */ 1073 function _normalize_name($name, $version) 1074 { 1075 $name = $name.'_'.$version; 1076 $name = str_replace(" ","_",$name); 1077 $name = preg_replace("/[^0-9A-Za-z\_]/",'',$name); 1078 return $name; 1079 } 1080 1081 /** 1082 * Generates a new minor version number 1083 * 1084 * @param string $version Current process version 1085 * @param bool $minor Generate minor version 1086 * @access private 1087 * @return string 1088 */ 1089 function _new_version($version,$minor=true) 1090 { 1091 $parts = explode('.',$version); 1092 if($minor) { 1093 $parts[count($parts)-1]++; 1094 } else { 1095 $parts[0]++; 1096 for ($i = 1; $i < count($parts); $i++) { 1097 $parts[$i] = 0; 1098 } 1099 } 1100 return implode('.',$parts); 1101 } 1102 1103 /** 1104 * Creates directory structure for process 1105 * 1106 * @param string $name Dir name in process repository 1107 * @access private 1108 * @return bool 1109 */ 1110 function _create_directory_structure($name) 1111 { 1112 $path = GALAXIA_PROCESSES.SEP.$name; 1113 if (!file_exists($path)) mkdir($path,0770); 1114 $path = GALAXIA_PROCESSES.SEP.$name.SEP."resources"; 1115 if (!file_exists($path)) mkdir($path,0770); 1116 $path = GALAXIA_PROCESSES.SEP.$name.SEP."graph"; 1117 if (!file_exists($path)) mkdir($path,0770); 1118 $path = GALAXIA_PROCESSES.SEP.$name.SEP."code"; 1119 if (!file_exists($path)) mkdir($path,0770); 1120 $path = GALAXIA_PROCESSES.SEP.$name.SEP."code".SEP."activities"; 1121 if (!file_exists($path)) mkdir($path,0770); 1122 $path = GALAXIA_PROCESSES.SEP.$name.SEP."code".SEP."templates"; 1123 if (!file_exists($path)) mkdir($path,0770); 1124 $path = GALAXIA_PROCESSES.SEP.$name.SEP."code".SEP."jobs"; 1125 if (!file_exists($path)) mkdir($path,0770); 1126 $path = GALAXIA_PROCESSES.SEP.$name.SEP."smarty"; 1127 if (!file_exists($path)) mkdir($path,0770); 1128 $path = GALAXIA_PROCESSES.SEP.$name.SEP."smarty".SEP."cache"; 1129 if (!file_exists($path)) mkdir($path,0770); 1130 $path = GALAXIA_PROCESSES.SEP.$name.SEP."smarty".SEP."compiled"; 1131 if (!file_exists($path)) mkdir($path,0770); 1132 if (GALAXIA_TEMPLATES) { 1133 $path = GALAXIA_TEMPLATES.SEP.$name; 1134 if (!file_exists($path)) mkdir($path,0770); 1135 } 1136 // Create shared file 1137 $file = GALAXIA_PROCESSES.SEP.$name.SEP."code".SEP."shared.php"; 1138 if (!file_exists($file)) 1139 { 1140 $fp = fopen(GALAXIA_PROCESSES.SEP.$name.SEP."code".SEP."shared.php","w"); 1141 if (!fp) return false; 1142 fwrite($fp,'<'.'?'.'php'."\n".'?'.'>'); 1143 fclose($fp); 1144 } 1145 } 1146 1147 /** 1148 * Removes a directory recursively 1149 * 1150 * @param string $dir Dir name to be erased 1151 * @param bool $rec Recursive mode 1152 * @access private 1153 * @return void 1154 */ 1155 function _remove_directory($dir,$rec=false) 1156 { 1157 // Prevent a disaster 1158 if(trim($dir) == SEP || trim($dir)=='.' || trim($dir)=='templates' || trim($dir)=='templates'.SEP) return false; 1159 $h = opendir($dir); 1160 while(($file = readdir($h)) != false) { 1161 if(is_file($dir.SEP.$file)) { 1162 @unlink($dir.SEP.$file); 1163 } else { 1164 if($rec && $file != '.' && $file != '..') { 1165 $this->_remove_directory($dir.SEP.$file, true); 1166 } 1167 } 1168 } 1169 closedir($h); 1170 @rmdir($dir); 1171 @unlink($dir); 1172 } 1173 1174 /** 1175 * Copies a directory recursively 1176 * 1177 * @param string $dir1 Dir name to be copied 1178 * @param string $dir2 Generated destination dir 1179 * @access private 1180 * @return void 1181 */ 1182 function _rec_copy($dir1,$dir2) 1183 { 1184 @mkdir($dir2,0777); 1185 $h = opendir($dir1); 1186 while(($file = readdir($h)) !== false) { 1187 if(is_file($dir1.SEP.$file)) { 1188 copy($dir1.SEP.$file,$dir2.SEP.$file); 1189 } else { 1190 if($file != '.' && $file != '..') { 1191 $this->_rec_copy($dir1.SEP.$file, $dir2.SEP.$file); 1192 } 1193 } 1194 } 1195 closedir($h); 1196 } 1197 1198 /** 1199 * XML parser start element handler 1200 * 1201 * @param resource $parser Parser handle 1202 * @param string $element XML tag 1203 * @param array $attribs XML tag attributes 1204 * @access private 1205 * @return void 1206 */ 1207 function _start_element_handler($parser, $element, $attribs) 1208 { 1209 $aux=Array('name'=>$element, 1210 'data'=>'', 1211 'parent' => $this->current, 1212 'children'=>Array(), 1213 'attribs' => $attribs); 1214 1215 $i = count($this->tree); 1216 $this->tree[$i] = $aux; 1217 1218 $this->tree[$this->current]['children'][]=$i; 1219 $this->current=$i; 1220 } 1221 1222 /** 1223 * XML parser end element handler 1224 * 1225 * @param resource $parser Parser handle 1226 * @param string $element XML tag 1227 * @param array $attribs XML tag attributes 1228 * @access private 1229 * @return void 1230 */ 1231 function _end_element_handler($parser, $element) 1232 { 1233 //when a tag ends put text 1234 $this->tree[$this->current]['data']=$this->buffer; 1235 $this->buffer=''; 1236 $this->current=$this->tree[$this->current]['parent']; 1237 } 1238 1239 /** 1240 * XML parser element data handler 1241 * 1242 * @param resource $parser Parser handle 1243 * @param string $element XML tag 1244 * @param string $data XML tag content 1245 * @access private 1246 * @return void 1247 */ 1248 function _data_handler($parser, $data) 1249 { 1250 $this->buffer .= $data; 1251 } 1252 1253 /** 1254 * This getConfigValues differs from the Process::getConfigValues because requires only process id. 1255 * This method gets the items defined in process_config table for this process, in fact this admin function bypass 1256 * the process behaviour and is just showing you the basic content of the table. 1257 * All config items are returned as a function result. 1258 * 1259 * @param int $pId Process id 1260 * @param bool $distinct_types If the distinct_type is set the returned array will follow the format: 1261 * * 0 =>('wf_config_name'=> 'foo') 1262 * =>('wf_config_value'=>'bar') 1263 * =>('wf_config_vale_int'=>null) 1264 * * 1 =>('wf_config_name' => 'toto') 1265 * =>('wf_config_value'=>'') 1266 * =>('wf_config_vale_int'=>15) 1267 * if set to false (default) the result array will be (note that this is the default result if having just the $pId): 1268 * * 'foo'=>'bar' 1269 * * 'toto'=>15 1270 * @param bool $askProcessObject If the askProcessObject is set to true (false by default) then the ProcessManager will load a process 1271 * object to run directly Process->getConfigValues($config_ask_array) this let you use this ProcessManager 1272 * getConfigValues the same way you would use $process->getConfigValues, with initialisation of default values. 1273 * you should then call this function this way: $conf_result=$pm->getConfigValues($pId,true,true,$my_conf_array) 1274 * @param array $config_array 1275 * @access public 1276 * @return array 1277 */ 1278 function getConfigValues($pId, $distinct_types=false, $askProcessObject=false, $config_array=array()) 1279 { 1280 if (!$askProcessObject) 1281 { 1282 $query = 'select * from '.GALAXIA_TABLE_PREFIX.'process_config where wf_p_id=?'; 1283 $result = $this->query($query, array($pId)); 1284 $result_array=array(); 1285 while($res = $result->fetchRow()) 1286 { 1287 if ( (!$distinct_types) ) 1288 {// we want a simple array 1289 if ($res['wf_config_value_int']==null) 1290 { 1291 $result_array[$res['wf_config_name']] = $res['wf_config_value']; 1292 } 1293 else 1294 { 1295 $result_array[$res['wf_config_name']] = $res['wf_config_value_int']; 1296 } 1297 } 1298 else 1299 {// build a more complex result array, which is just the table rows 1300 $result_array[] = $res; 1301 } 1302 } 1303 } 1304 else //we'll load a Process object and let him work for us 1305 { 1306 //Warning: this means you have to include the Process.php from the API 1307 $this->Process = new Process($this->db); 1308 $this->Process->getProcess($pId); 1309 $result_array = $this->Process->getConfigValues($config_array); 1310 unset ($this->Process); 1311 } 1312 return $result_array; 1313 } 1314 1315 /** 1316 * Calls a process object to save his new config values by taking a process Id as first argument and simply call 1317 * this process's setConfigValues method. We let the process define the better way to store the data given as second arg. 1318 * 1319 * @param int $pId Process id 1320 * @param array &$config_array 1321 * @return void 1322 * @access public 1323 */ 1324 function setConfigValues($pId, &$config_array) 1325 { 1326 //Warning: this means you have to include the Process.php from the API 1327 $this->Process = new Process($this->db); 1328 $this->Process->getProcess($pId); 1329 $this->Process->setConfigValues($config_array); 1330 unset ($this->Process); 1331 } 1332 1333 /** 1334 * Gets available agents list 1335 * 1336 * @return array 1337 * @access public 1338 */ 1339 function get_agents() 1340 { 1341 return galaxia_get_agents_list(); 1342 } 1343 1344 /** 1345 * Gets the view activity id avaible for a given process 1346 * 1347 * @param int $pId Process Id 1348 * @return bool False if no view activity is avaible for the process, return the activity id if there is one 1349 * @access public 1350 */ 1351 function get_process_view_activity($pId) 1352 { 1353 $mid = 'where gp.wf_p_id=? and ga.wf_type=?'; 1354 $bindvars = array($pId,'view'); 1355 $query = 'select ga.wf_activity_id 1356 from '.GALAXIA_TABLE_PREFIX.'processes gp 1357 INNER JOIN '.GALAXIA_TABLE_PREFIX."activities ga ON gp.wf_p_id=ga.wf_p_id 1358 $mid"; 1359 $result = $this->query($query,$bindvars); 1360 $ret = Array(); 1361 $retval = false; 1362 if (!(empty($result))) 1363 { 1364 while($res = $result->fetchRow()) 1365 { 1366 $retval = $res['wf_activity_id']; 1367 } 1368 } 1369 return $retval; 1370 } 840 function invalidate_process($pid) 841 { 842 $query = 'update '.GALAXIA_TABLE_PREFIX.'processes set wf_is_valid=? where wf_p_id=?'; 843 $this->query($query, array('n',$pid)); 844 } 845 846 /** 847 * Removes a process by pId 848 * 849 * @param int $pId Process id 850 * @return bool 851 * @access public 852 */ 853 function remove_process($pId) 854 { 855 if (!(isset($this->activity_manager))) $this->activity_manager = new ActivityManager($this->db); 856 if (!isset($this->jobManager)) 857 $this->jobManager = new JobManager($this->db); 858 $this->deactivate_process($pId); 859 $name = $this->_get_normalized_name($pId); 860 861 // start a transaction 862 $this->db->StartTrans(); 863 $this->jobManager->removeJobsByProcessID($pId); 864 865 // Remove process activities 866 $query = 'select wf_activity_id from '.GALAXIA_TABLE_PREFIX.'activities where wf_p_id=?'; 867 $result = $this->query($query, array($pId)); 868 while($res = $result->fetchRow()) { 869 //we add a false parameter to prevent the ActivityManager from opening a new transaction 870 $this->activity_manager->remove_activity($pId,$res['wf_activity_id'], false); 871 } 872 873 // Remove process roles 874 $query = 'delete from '.GALAXIA_TABLE_PREFIX.'roles where wf_p_id=?'; 875 $this->query($query, array($pId)); 876 $query = 'delete from '.GALAXIA_TABLE_PREFIX.'user_roles where wf_p_id=?'; 877 $this->query($query, array($pId)); 878 879 // Remove process instances 880 $query = 'delete from '.GALAXIA_TABLE_PREFIX.'instances where wf_p_id=?'; 881 $this->query($query, array($pId)); 882 883 // Remove the directory structure 884 if (!empty($name) && is_dir(GALAXIA_PROCESSES.SEP.$name)) { 885 $this->_remove_directory(GALAXIA_PROCESSES.SEP.$name,true); 886 } 887 if (GALAXIA_TEMPLATES && !empty($name) && is_dir(GALAXIA_TEMPLATES.SEP.$name)) { 888 $this->_remove_directory(GALAXIA_TEMPLATES.SEP.$name,true); 889 } 890 891 // Remove configuration data 892 $query = 'delete from '.GALAXIA_TABLE_PREFIX.'process_config where wf_p_id=?'; 893 $this->query($query, array($pId)); 894 895 // And finally remove the proc 896 $query = 'delete from '.GALAXIA_TABLE_PREFIX.'processes where wf_p_id=?'; 897 $this->query($query, array($pId)); 898 $msg = sprintf(tra('Process %s removed'),$name); 899 $this->error[] = $msg; 900 901 // perform commit (return true) or Rollback (return false) 902 return $this->db->CompleteTrans(); 903 904 } 905 906 /** 907 * Updates or inserts a new process in the database, $vars is an associative array containing the fields to update or to insert as needed. 908 * Configuration options should be in an array associated with the 'config' key 909 * this config array should contain 'wf_config_name', 'wf_config_value' and 'wf_config_value_int' keys. 910 * $pId is the processI. If $pId is 0 then we create a new process, else we are in edit mode. 911 * if $create is true start and end activities will be created (when importing use $create=false) 912 * 913 * @param int $pId Process id, if 0 then we create a new process, else we are in edit mode 914 * @param array &$vars Associative containing the fields to update or to insert as needed 915 * @param bool $create If true, start and end activities will be created (when importing use $create=false). 916 * @return int Process id 917 * @access public 918 */ 919 function replace_process($pId, &$vars, $create = true) 920 { 921 if (!(isset($this->activity_manager))) $this->activity_manager = new ActivityManager($this->db); 922 $TABLE_NAME = GALAXIA_TABLE_PREFIX.'processes'; 923 $now = date("U"); 924 $vars['wf_last_modif']=$now; 925 $vars['wf_normalized_name'] = $this->_normalize_name($vars['wf_name'],$vars['wf_version']); 926 $config_array = array(); 927 928 foreach($vars as $key=>$value) 929 { 930 if ($key=='config') 931 { 932 $config_array_init =& $value; 933 // rebuild a nice config_array with type of config and value 934 if( is_array($config_array_init) && count($config_array_init) > 0 ) 935 { 936 foreach($config_array_init as $config) 937 { 938 if (isset($config['wf_config_value_int']) && (!($config['wf_config_value_int']==''))) 939 { 940 $config_array[$config['wf_config_name']] = array('int' => $config['wf_config_value_int']); 941 } 942 else 943 { 944 if (isset($config['wf_config_value'])) 945 { 946 $config_array[$config['wf_config_name']] = array('text' => $config['wf_config_value']); 947 } 948 } 949 } 950 } 951 //no need to keep it in the vars array, this array is used in queries 952 unset($vars['config']); 953 } 954 else // not config, it's just process's fields values 955 { 956 $vars[$key]=addslashes($value); 957 } 958 } 959 960 if($pId) { 961 // update mode 962 $old_proc = $this->get_process($pId); 963 $first = true; 964 $query ="update $TABLE_NAME set"; 965 foreach($vars as $key=>$value) { 966 if(!$first) $query.= ','; 967 if(!is_numeric($value)||strstr($value,'.')) $value="'".$value."'"; 968 $query.= " $key=$value "; 969 $first = false; 970 } 971 $query .= " where wf_p_id=$pId "; 972 $this->query($query); 973 974 //set config values 975 $this->setConfigValues($pId,$config_array); 976 977 // Note that if the name is being changed then 978 // the directory has to be renamed! 979 $oldname = $old_proc['wf_normalized_name']; 980 $newname = $vars['wf_normalized_name']; 981 if ($newname != $oldname) { 982 rename(GALAXIA_PROCESSES.SEP."$oldname",GALAXIA_PROCESSES.SEP."$newname"); 983 } 984 $msg = sprintf(tra('Process %s has been updated'),$vars['wf_name']); 985 $this->error[] = $msg; 986 } else { 987 unset($vars['wf_p_id']); 988 // insert mode 989 $name = $this->_normalize_name($vars['wf_name'],$vars['wf_version']); 990 $this->_create_directory_structure($name); 991 $first = true; 992 $query = "insert into $TABLE_NAME("; 993 foreach(array_keys($vars) as $key) { 994 if(!$first) $query.= ','; 995 $query.= "$key"; 996 $first = false; 997 } 998 $query .=") values("; 999 $first = true; 1000 foreach(array_values($vars) as $value) { 1001 if(!$first) $query.= ','; 1002 if(!is_numeric($value)||strstr($value,'.')) $value="'".$value."'"; 1003 $query.= "$value"; 1004 $first = false; 1005 } 1006 $query .=")"; 1007 $this->query($query); 1008 //FIXME: this query seems to be quite sure to get a result, I would prefer something 1009 // more sure to get the right result everytime 1010 $pId = $this->getOne("select max(wf_p_id) from $TABLE_NAME where wf_last_modif=$now"); 1011 1012 //set config values 1013 $this->setConfigValues($pId,$config_array); 1014 1015 // Now automatically add a start and end activity 1016 // unless importing ($create = false) 1017 if($create) { 1018 $vars1 = Array( 1019 'wf_name' => 'start', 1020 'wf_description' => 'default start activity', 1021 'wf_type' => 'start', 1022 'wf_is_interactive' => 'y', 1023 'wf_is_autorouted' => 'y' 1024 ); 1025 $vars2 = Array( 1026 'wf_name' => 'end', 1027 'wf_description' => 'default end activity', 1028 'wf_type' => 'end', 1029 'wf_is_interactive' => 'n', 1030 'wf_is_autorouted' => 'y' 1031 ); 1032 1033 $this->activity_manager->replace_activity($pId,0,$vars1); 1034 $this->activity_manager->replace_activity($pId,0,$vars2); 1035 } 1036 $msg = sprintf(tra('Process %s has been created'),$vars['wf_name']); 1037 $this->error[] = $msg; 1038 } 1039 // Get the id 1040 return $pId; 1041 } 1042 1043 /** 1044 * Gets the normalized name of a process by pid 1045 * 1046 * @param int $pId Process id 1047 * @access private 1048 * @return string 1049 */ 1050 function _get_normalized_name($pId) 1051 { 1052 $info = $this->get_process($pId); 1053 return $info['wf_normalized_name']; 1054 } 1055 1056 /** 1057 * Normalizes a process name 1058 * 1059 * @param string $name Process name to be normalized 1060 * @param string $version Process version 1061 * @access private 1062 * @return string Process normalized name 1063 */ 1064 function _normalize_name($name, $version) 1065 { 1066 $name = $name.'_'.$version; 1067 $name = str_replace(" ","_",$name); 1068 $name = preg_replace("/[^0-9A-Za-z\_]/",'',$name); 1069 return $name; 1070 } 1071 1072 /** 1073 * Generates a new minor version number 1074 * 1075 * @param string $version Current process version 1076 * @param bool $minor Generate minor version 1077 * @access private 1078 * @return string 1079 */ 1080 function _new_version($version,$minor=true) 1081 { 1082 $parts = explode('.',$version); 1083 if($minor) { 1084 $parts[count($parts)-1]++; 1085 } else { 1086 $parts[0]++; 1087 for ($i = 1; $i < count($parts); $i++) { 1088 $parts[$i] = 0; 1089 } 1090 } 1091 return implode('.',$parts); 1092 } 1093 1094 /** 1095 * Creates directory structure for process 1096 * 1097 * @param string $name Dir name in process repository 1098 * @access private 1099 * @return bool 1100 */ 1101 function _create_directory_structure($name) 1102 { 1103 $path = GALAXIA_PROCESSES.SEP.$name; 1104 if (!file_exists($path)) mkdir($path,0770); 1105 $path = GALAXIA_PROCESSES.SEP.$name.SEP."resources"; 1106 if (!file_exists($path)) mkdir($path,0770); 1107 $path = GALAXIA_PROCESSES.SEP.$name.SEP."graph"; 1108 if (!file_exists($path)) mkdir($path,0770); 1109 $path = GALAXIA_PROCESSES.SEP.$name.SEP."code"; 1110 if (!file_exists($path)) mkdir($path,0770); 1111 $path = GALAXIA_PROCESSES.SEP.$name.SEP."code".SEP."activities"; 1112 if (!file_exists($path)) mkdir($path,0770); 1113 $path = GALAXIA_PROCESSES.SEP.$name.SEP."code".SEP."templates"; 1114 if (!file_exists($path)) mkdir($path,0770); 1115 $path = GALAXIA_PROCESSES.SEP.$name.SEP."code".SEP."jobs"; 1116 if (!file_exists($path)) mkdir($path,0770); 1117 $path = GALAXIA_PROCESSES.SEP.$name.SEP."smarty"; 1118 if (!file_exists($path)) mkdir($path,0770); 1119 $path = GALAXIA_PROCESSES.SEP.$name.SEP."smarty".SEP."cache"; 1120 if (!file_exists($path)) mkdir($path,0770); 1121 $path = GALAXIA_PROCESSES.SEP.$name.SEP."smarty".SEP."compiled"; 1122 if (!file_exists($path)) mkdir($path,0770); 1123 if (GALAXIA_TEMPLATES) { 1124 $path = GALAXIA_TEMPLATES.SEP.$name; 1125 if (!file_exists($path)) mkdir($path,0770); 1126 } 1127 // Create shared file 1128 $file = GALAXIA_PROCESSES.SEP.$name.SEP."code".SEP."shared.php"; 1129 if (!file_exists($file)) 1130 { 1131 $fp = fopen(GALAXIA_PROCESSES.SEP.$name.SEP."code".SEP."shared.php","w"); 1132 if (!fp) return false; 1133 fwrite($fp,'<'.'?'.'php'."\n".'?'.'>'); 1134 fclose($fp); 1135 } 1136 } 1137 1138 /** 1139 * Removes a directory recursively 1140 * 1141 * @param string $dir Dir name to be erased 1142 * @param bool $rec Recursive mode 1143 * @access private 1144 * @return void 1145 */ 1146 function _remove_directory($dir,$rec=false) 1147 { 1148 // Prevent a disaster 1149 if(trim($dir) == SEP || trim($dir)=='.' || trim($dir)=='templates' || trim($dir)=='templates'.SEP) return false; 1150 $h = opendir($dir); 1151 while(($file = readdir($h)) != false) { 1152 if(is_file($dir.SEP.$file)) { 1153 @unlink($dir.SEP.$file); 1154 } else { 1155 if($rec && $file != '.' && $file != '..') { 1156 $this->_remove_directory($dir.SEP.$file, true); 1157 } 1158 } 1159 } 1160 closedir($h); 1161 @rmdir($dir); 1162 @unlink($dir); 1163 } 1164 1165 /** 1166 * Copies a directory recursively 1167 * 1168 * @param string $dir1 Dir name to be copied 1169 * @param string $dir2 Generated destination dir 1170 * @access private 1171 * @return void 1172 */ 1173 function _rec_copy($dir1,$dir2) 1174 { 1175 @mkdir($dir2,0777); 1176 $h = opendir($dir1); 1177 while(($file = readdir($h)) !== false) { 1178 if(is_file($dir1.SEP.$file)) { 1179 copy($dir1.SEP.$file,$dir2.SEP.$file); 1180 } else { 1181 if($file != '.' && $file != '..') { 1182 $this->_rec_copy($dir1.SEP.$file, $dir2.SEP.$file); 1183 } 1184 } 1185 } 1186 closedir($h); 1187 } 1188 1189 /** 1190 * XML parser start element handler 1191 * 1192 * @param resource $parser Parser handle 1193 * @param string $element XML tag 1194 * @param array $attribs XML tag attributes 1195 * @access private 1196 * @return void 1197 */ 1198 function _start_element_handler($parser, $element, $attribs) 1199 { 1200 $aux=Array('name'=>$element, 1201 'data'=>'', 1202 'parent' => $this->current, 1203 'children'=>Array(), 1204 'attribs' => $attribs); 1205 1206 $i = count($this->tree); 1207 $this->tree[$i] = $aux; 1208 1209 $this->tree[$this->current]['children'][]=$i; 1210 $this->current=$i; 1211 } 1212 1213 /** 1214 * XML parser end element handler 1215 * 1216 * @param resource $parser Parser handle 1217 * @param string $element XML tag 1218 * @param array $attribs XML tag attributes 1219 * @access private 1220 * @return void 1221 */ 1222 function _end_element_handler($parser, $element) 1223 { 1224 //when a tag ends put text 1225 $this->tree[$this->current]['data']=$this->buffer; 1226 $this->buffer=''; 1227 $this->current=$this->tree[$this->current]['parent']; 1228 } 1229 1230 /** 1231 * XML parser element data handler 1232 * 1233 * @param resource $parser Parser handle 1234 * @param string $element XML tag 1235 * @param string $data XML tag content 1236 * @access private 1237 * @return void 1238 */ 1239 function _data_handler($parser, $data) 1240 { 1241 $this->buffer .= $data; 1242 } 1243 1244 /** 1245 * This getConfigValues differs from the Process::getConfigValues because requires only process id. 1246 * This method gets the items defined in process_config table for this process, in fact this admin function bypass 1247 * the process behaviour and is just showing you the basic content of the table. 1248 * All config items are returned as a function result. 1249 * 1250 * @param int $pId Process id 1251 * @param bool $distinct_types If the distinct_type is set the returned array will follow the format: 1252 * * 0 =>('wf_config_name'=> 'foo') 1253 * =>('wf_config_value'=>'bar') 1254 * =>('wf_config_vale_int'=>null) 1255 * * 1 =>('wf_config_name' => 'toto') 1256 * =>('wf_config_value'=>'') 1257 * =>('wf_config_vale_int'=>15) 1258 * if set to false (default) the result array will be (note that this is the default result if having just the $pId): 1259 * * 'foo'=>'bar' 1260 * * 'toto'=>15 1261 * @param bool $askProcessObject If the askProcessObject is set to true (false by default) then the ProcessManager will load a process 1262 * object to run directly Process->getConfigValues($config_ask_array) this let you use this ProcessManager 1263 * getConfigValues the same way you would use $process->getConfigValues, with initialisation of default values. 1264 * you should then call this function this way: $conf_result=$pm->getConfigValues($pId,true,true,$my_conf_array) 1265 * @param array $config_array 1266 * @access public 1267 * @return array 1268 */ 1269 function getConfigValues($pId, $distinct_types=false, $askProcessObject=false, $config_array=array()) 1270 { 1271 if (!$askProcessObject) 1272 { 1273 $query = 'select * from '.GALAXIA_TABLE_PREFIX.'process_config where wf_p_id=?'; 1274 $result = $this->query($query, array($pId)); 1275 $result_array=array(); 1276 while($res = $result->fetchRow()) 1277 { 1278 if ( (!$distinct_types) ) 1279 {// we want a simple array 1280 if ($res['wf_config_value_int']==null) 1281 { 1282 $result_array[$res['wf_config_name']] = $res['wf_config_value']; 1283 } 1284 else 1285 { 1286 $result_array[$res['wf_config_name']] = $res['wf_config_value_int']; 1287 } 1288 } 1289 else 1290 {// build a more complex result array, which is just the table rows 1291 $result_array[] = $res; 1292 } 1293 } 1294 } 1295 else //we'll load a Process object and let him work for us 1296 { 1297 //Warning: this means you have to include the Process.php from the API 1298 $this->Process = new Process($this->db); 1299 $this->Process->getProcess($pId); 1300 $result_array = $this->Process->getConfigValues($config_array); 1301 unset ($this->Process); 1302 } 1303 return $result_array; 1304 } 1305 1306 /** 1307 * Calls a process object to save his new config values by taking a process Id as first argument and simply call 1308 * this process's setConfigValues method. We let the process define the better way to store the data given as second arg. 1309 * 1310 * @param int $pId Process id 1311 * @param array &$config_array 1312 * @return void 1313 * @access public 1314 */ 1315 function setConfigValues($pId, &$config_array) 1316 { 1317 //Warning: this means you have to include the Process.php from the API 1318 $this->Process = new Process($this->db); 1319 $this->Process->getProcess($pId); 1320 $this->Process->setConfigValues($config_array); 1321 unset ($this->Process); 1322 } 1323 1324 /** 1325 * Gets available agents list 1326 * 1327 * @return array 1328 * @access public 1329 */ 1330 function get_agents() 1331 { 1332 return galaxia_get_agents_list(); 1333 } 1334 1335 /** 1336 * Gets the view activity id avaible for a given process 1337 * 1338 * @param int $pId Process Id 1339 * @return bool False if no view activity is avaible for the process, return the activity id if there is one 1340 * @access public 1341 */ 1342 function get_process_view_activity($pId) 1343 { 1344 $mid = 'where gp.wf_p_id=? and ga.wf_type=?'; 1345 $bindvars = array($pId,'view'); 1346 $query = 'select ga.wf_activity_id 1347 from '.GALAXIA_TABLE_PREFIX.'processes gp 1348 INNER JOIN '.GALAXIA_TABLE_PREFIX."activities ga ON gp.wf_p_id=ga.wf_p_id 1349 $mid"; 1350 $result = $this->query($query,$bindvars); 1351 $ret = Array(); 1352 $retval = false; 1353 if (!(empty($result))) 1354 { 1355 while($res = $result->fetchRow()) 1356 { 1357 $retval = $res['wf_activity_id']; 1358 } 1359 } 1360 return $retval; 1361 } 1371 1362 1372 1363 } -
sandbox/workflow/branches/603/inc/engine/src/common/Base.php
r795 r2129 1 1 <?php 2 require_once(GALAXIA_LIBRARY.SEP.'src'.SEP.'common'.SEP.'Observable.php');3 2 /** 4 3 * This class is derived by all the API classes so they get the 5 4 * database connection, database methods and the Observable interface 6 * 5 * 7 6 * @package Galaxia 8 * @license http://www.gnu.org/copyleft/gpl.html GPL 7 * @license http://www.gnu.org/copyleft/gpl.html GPL 9 8 */ 10 class Base extends Observable{9 class Base { 11 10 /** 12 11 * @var object $db Database abstraction object used to access the database … … 17 16 * @var int $num_queries Debugging var 18 17 * @access private 19 */ 18 */ 20 19 var $num_queries = 0; 21 20 /** 22 21 * @var int $num_queries_total Debugging var 23 22 * @access private 24 */ 23 */ 25 24 var $num_queries_total = 0; 26 25 /** 27 26 * @var array $error Error messages 28 27 * @access public 29 */ 28 */ 30 29 var $error= Array(); 31 30 /** … … 39 38 */ 40 39 var $child_name = 'Base'; 41 40 42 41 /** 43 42 * Constructor receiving a database abstraction object … … 72 71 * Always call this function after failed operations on a workflow object to obtain messages 73 72 * 74 * @param bool $as_array if true the result will be send as an array of errors or an empty array. Else, if you do not give any parameter 73 * @param bool $as_array if true the result will be send as an array of errors or an empty array. Else, if you do not give any parameter 75 74 * or give a false parameter you will obtain a single string which can be empty or will contain error messages with <br /> html tags 76 75 * @param bool $debug is false by default, if true you wil obtain more messages 77 76 * @param string $prefix string appended to the debug message 78 77 * @return mixed Error and debug messages or an array of theses messages and empty the error messages 79 * @access public 78 * @access public 80 79 */ 81 function get_error($as_array=false, $debug=false, $prefix='') 80 function get_error($as_array=false, $debug=false, $prefix='') 82 81 { 83 82 //collect errors from used objects … … 96 95 /** 97 96 * Gets warnings recorded by this object 98 * 99 * @param bool $as_array if true the result will be send as an array of warnings or an empty array. Else, if you do not give any parameter 97 * 98 * @param bool $as_array if true the result will be send as an array of warnings or an empty array. Else, if you do not give any parameter 100 99 * or give a false parameter you will obtain a single string which can be empty or will contain warning messages with <br /> html tags 101 100 * @return mixed Warning messages or an array of theses messages and empty the warning messages 102 * @access public 101 * @access public 103 102 */ 104 function get_warning($as_array=false) 103 function get_warning($as_array=false) 105 104 { 106 105 if ($as_array) … … 118 117 * Collect errors from all linked objects which could have been used by this object 119 118 * Each child class should instantiate this function with her linked objetcs, calling get_error(true) 120 * 119 * 121 120 * @param bool $debug is false by default, if true debug messages can be added to 'normal' messages 122 121 * @param string $prefix is a string appended to the debug message 123 122 * @abstract 124 123 * @access public 125 * @return void 124 * @return void 126 125 */ 127 126 function collect_errors($debug=false, $prefix = '') … … 134 133 } 135 134 } 136 135 137 136 /** 138 137 * Performs a query on the AdoDB database object 139 * 138 * 140 139 * @param string $query sql query, parameters should be replaced with ? 141 140 * @param array $values array containing the parameters (going in the ?), use it to avoid security problems. If … … 196 195 197 196 /** 198 * @see Base::query 197 * @see Base::query 199 198 * @param string $query sql query, parameters should be replaced with ? 200 199 * @param array $values array containing the parameters (going in the ?), use it to avoid security problems … … 224 223 if (!$result && $reporterrors ) 225 224 $this->sql_error($query, $clean_values, $result); 226 if (!!$result) 225 if (!!$result) 227 226 { 228 227 $res = $result->fetchRow(); … … 241 240 /** 242 241 * Throws error warnings 243 * 242 * 244 243 * @param string $query 245 244 * @param array $values 246 245 * @param mixed $result 247 246 * @access public 248 * @return void 247 * @return void 249 248 */ 250 249 function sql_error($query, $values, $result) { … … 252 251 // DO NOT DIE, if transactions are there, they will do things in a better way 253 252 } 254 253 255 254 /** 256 255 * Clean the data before it is recorded on the database 257 * 256 * 258 257 * @param $value is a data we want to be stored in the database. 259 * If it is an array we'll make a serialize and then an base64_encode 258 * If it is an array we'll make a serialize and then an base64_encode 260 259 * (you'll have to make an unserialize(base64_decode()) 261 260 * If it is not an array we make an htmlspecialchars() on it … … 292 291 /** 293 292 * Supports DB abstraction 294 * 293 * 295 294 * @param string &$query 296 * @return void 295 * @return void 297 296 * @access public 298 297 */ … … 302 301 case "oci8": 303 302 $query = preg_replace("/`/", "\"", $query); 304 // convert bind variables - adodb does not do that 303 // convert bind variables - adodb does not do that 305 304 $qe = explode("?", $query); 306 305 $query = ''; … … 318 317 /** 319 318 * Supports DB abstraction 320 * 319 * 321 320 * @param string $sort_mode 322 * @return string 321 * @return string 323 322 * @access public 324 323 */ … … 330 329 /** 331 330 * Supports DB abstraction 332 * 333 * @return mixed 331 * 332 * @return mixed 334 333 * @access public 335 334 */
Note: See TracChangeset
for help on using the changeset viewer.