00001 <?php
00002 include_once(GALAXIA_LIBRARY.'/src/ProcessManager/BaseManager.php');
00005
00009 class ProcessManager extends BaseManager {
00010 var $parser;
00011 var $tree;
00012 var $current;
00013 var $buffer;
00014
00019 function ProcessManager($db)
00020 {
00021 if(!$db) {
00022 die("Invalid db object passed to ProcessManager constructor");
00023 }
00024 $this->db = $db;
00025 }
00026
00030 function activate_process($pId)
00031 {
00032 $query = "update ".GALAXIA_TABLE_PREFIX."processes set isActive='y' where pId=$pId";
00033 $this->query($query);
00034 $msg = sprintf(tra('Process %d has been activated'),$pId);
00035 $this->notify_all(3,$msg);
00036 }
00037
00041 function deactivate_process($pId)
00042 {
00043 $query = "update ".GALAXIA_TABLE_PREFIX."processes set isActive='n' where pId=$pId";
00044 $this->query($query);
00045 $msg = sprintf(tra('Process %d has been deactivated'),$pId);
00046 $this->notify_all(3,$msg);
00047 }
00048
00052 function serialize_process($pId)
00053 {
00054
00055 $out = '<process>'."\n";
00056 $proc_info = $this->get_process($pId);
00057 $procname = $proc_info['normalized_name'];
00058 $out.= ' <name>'.htmlspecialchars($proc_info['name']).'</name>'."\n";
00059 $out.= ' <isValid>'.htmlspecialchars($proc_info['isValid']).'</isValid>'."\n";
00060 $out.= ' <version>'.htmlspecialchars($proc_info['version']).'</version>'."\n";
00061 $out.= ' <isActive>'.htmlspecialchars($proc_info['isActive']).'</isActive>'."\n";
00062 $out.=' <description>'.htmlspecialchars($proc_info['description']).'</description>'."\n";
00063 $out.= ' <lastModif>'.date("d/m/Y [h:i:s]",$proc_info['lastModif']).'</lastModif>'."\n";
00064 $out.= ' <sharedCode><![CDATA[';
00065 $fp=fopen(GALAXIA_PROCESSES."/$procname/code/shared.php","r");
00066 while(!feof($fp)) {
00067 $line=fread($fp,8192);
00068 $out.=$line;
00069 }
00070 fclose($fp);
00071 $out.= ' ]]></sharedCode>'."\n";
00072
00073 $query = "select * from ".GALAXIA_TABLE_PREFIX."activities where pId=$pId";
00074 $result = $this->query($query);
00075 $out.=' <activities>'."\n";
00076 $am = new ActivityManager($this->db);
00077 while($res = $result->fetchRow()) {
00078 $name = $res['normalized_name'];
00079 $out.=' <activity>'."\n";
00080 $out.=' <name>'.htmlspecialchars($res['name']).'</name>'."\n";
00081 $out.=' <type>'.htmlspecialchars($res['type']).'</type>'."\n";
00082 $out.=' <description>'.htmlspecialchars($res['description']).'</description>'."\n";
00083 $out.=' <lastModif>'.date("d/m/Y [h:i:s]",$res['lastModif']).'</lastModif>'."\n";
00084 $out.=' <isInteractive>'.$res['isInteractive'].'</isInteractive>'."\n";
00085 $out.=' <isAutoRouted>'.$res['isAutoRouted'].'</isAutoRouted>'."\n";
00086 $out.=' <roles>'."\n";
00087
00088 $roles = $am->get_activity_roles($res['activityId']);
00089 foreach($roles as $role) {
00090 $out.=' <role>'.htmlspecialchars($role['name']).'</role>'."\n";
00091 }
00092 $out.=' </roles>'."\n";
00093 $out.=' <code><![CDATA[';
00094 $fp=fopen(GALAXIA_PROCESSES."/$procname/code/activities/$name.php","r");
00095 while(!feof($fp)) {
00096 $line=fread($fp,8192);
00097 $out.=$line;
00098 }
00099 fclose($fp);
00100 $out.=' ]]></code>';
00101 if($res['isInteractive']=='y') {
00102 $out.=' <template><![CDATA[';
00103 $fp=fopen(GALAXIA_PROCESSES."/$procname/code/templates/$name.tpl","r");
00104 while(!feof($fp)) {
00105 $line=fread($fp,8192);
00106 $out.=$line;
00107 }
00108 fclose($fp);
00109 $out.=' ]]></template>';
00110 }
00111 $out.=' </activity>'."\n";
00112 }
00113 $out.=' </activities>'."\n";
00114 $out.=' <transitions>'."\n";
00115 $transitions = $am->get_process_transitions($pId);
00116 foreach($transitions as $tran) {
00117 $out.=' <transition>'."\n";
00118 $out.=' <from>'.htmlspecialchars($tran['actFromName']).'</from>'."\n";
00119 $out.=' <to>'.htmlspecialchars($tran['actToName']).'</to>'."\n";
00120 $out.=' </transition>'."\n";
00121 }
00122 $out.=' </transitions>'."\n";
00123 $out.= '</process>'."\n";
00124
00125
00126
00127 return $out;
00128 }
00129
00134 function unserialize_process($xml)
00135 {
00136
00137
00138
00139 $this->parser = xml_parser_create();
00140 xml_parser_set_option($this->parser,XML_OPTION_CASE_FOLDING,0);
00141 xml_set_object($this->parser, $this);
00142 xml_set_element_handler($this->parser, "_start_element_handler", "_end_element_handler");
00143 xml_set_character_data_handler($this->parser, "_data_handler");
00144 $aux=Array(
00145 'name'=>'root',
00146 'children'=>Array(),
00147 'parent' => 0,
00148 'data'=>''
00149 );
00150 $this->tree[0]=$aux;
00151 $this->current=0;
00152 if (!xml_parse($this->parser, $xml, true)) {
00153 $error = sprintf("XML error: %s at line %d",
00154 xml_error_string(xml_get_error_code($this->parser)),
00155 xml_get_current_line_number($this->parser));
00156 trigger_error($error,E_USER_WARNING);
00157 }
00158 xml_parser_free($this->parser);
00159
00160
00161 $process=Array();
00162 $activities=Array();
00163 $transitions=Array();
00164 for($i=0;$i<count($this->tree[1]['children']);$i++) {
00165
00166 $z=$this->tree[1]['children'][$i];
00167 $name = trim($this->tree[$z]['name']);
00168 if($name=='activities') {
00169 for($j=0;$j<count($this->tree[$z]['children']);$j++) {
00170 $z2 = $this->tree[$z]['children'][$j];
00171
00172 if($this->tree[$z2]['name']=='activity') {
00173 for($k=0;$k<count($this->tree[$z2]['children']);$k++) {
00174 $z3 = $this->tree[$z2]['children'][$k];
00175 $name = trim($this->tree[$z3]['name']);
00176 $value= trim($this->tree[$z3]['data']);
00177 if($name=='roles') {
00178 $roles=Array();
00179 for($l=0;$l<count($this->tree[$z3]['children']);$l++) {
00180 $z4 = $this->tree[$z3]['children'][$l];
00181 $name = trim($this->tree[$z4]['name']);
00182 $data = trim($this->tree[$z4]['data']);
00183 $roles[]=$data;
00184 }
00185 } else {
00186 $aux[$name]=$value;
00187
00188 }
00189 }
00190 $aux['roles']=$roles;
00191 $activities[]=$aux;
00192 }
00193 }
00194 } elseif($name=='transitions') {
00195 for($j=0;$j<count($this->tree[$z]['children']);$j++) {
00196 $z2 = $this->tree[$z]['children'][$j];
00197
00198 if($this->tree[$z2]['name']=='transition') {
00199 for($k=0;$k<count($this->tree[$z2]['children']);$k++) {
00200 $z3 = $this->tree[$z2]['children'][$k];
00201 $name = trim($this->tree[$z3]['name']);
00202 $value= trim($this->tree[$z3]['data']);
00203 if($name == 'from' || $name == 'to') {
00204 $aux[$name]=$value;
00205 }
00206 }
00207 }
00208 $transitions[] = $aux;
00209 }
00210 } else {
00211 $value = trim($this->tree[$z]['data']);
00212
00213 $process[$name]=$value;
00214 }
00215 }
00216 $process['activities']=$activities;
00217 $process['transitions']=$transitions;
00218 return $process;
00219 }
00220
00226 function import_process($data)
00227 {
00228
00229 $am = new ActivityManager($this->db);
00230 $rm = new RoleManager($this->db);
00231
00232 $vars = Array(
00233 'name' => $data['name'],
00234 'version' => $data['version'],
00235 'description' => $data['description'],
00236 'lastModif' => $data['lastModif'],
00237 'isActive' => $data['isActive'],
00238 'isValid' => $data['isValid']
00239 );
00240 $pid = $this->replace_process(0,$vars,false);
00241
00242 $proc_info = $this->get_process($pid);
00243 $procname = $proc_info['normalized_name'];
00244 $fp = fopen(GALAXIA_PROCESSES."/$procname/code/shared.php","w");
00245 fwrite($fp,$data['sharedCode']);
00246 fclose($fp);
00247 $actids = Array();
00248
00249 foreach($data['activities'] as $activity) {
00250 $vars = Array(
00251 'name' => $activity['name'],
00252 'description' => $activity['description'],
00253 'type' => $activity['type'],
00254 'lastModif' => $activity['lastModif'],
00255 'isInteractive' => $activity['isInteractive'],
00256 'isAutoRouted' => $activity['isAutoRouted']
00257 );
00258 $actname=$am->_normalize_name($activity['name']);
00259
00260 $actid = $am->replace_activity($pid,0,$vars);
00261 $fp = fopen(GALAXIA_PROCESSES."/$procname/code/activities/$actname".'.php',"w");
00262 fwrite($fp,$activity['code']);
00263 fclose($fp);
00264 if($activity['isInteractive']=='y') {
00265 $fp = fopen(GALAXIA_PROCESSES."/$procname/code/templates/$actname".'.tpl',"w");
00266 fwrite($fp,$activity['template']);
00267 fclose($fp);
00268 }
00269 $actids[$activity['name']] = $am->_get_activity_id_by_name($pid,$activity['name']);
00270 $actname = $am->_normalize_name($activity['name']);
00271 $now = date("U");
00272
00273 foreach($activity['roles'] as $role) {
00274 $vars = Array(
00275 'name' => $role,
00276 'description' => $role,
00277 'lastModif' => $now,
00278 );
00279 if(!$rm->role_name_exists($pid,$role)) {
00280 $rid=$rm->replace_role($pid,0,$vars);
00281 } else {
00282 $rid = $rm->get_role_id($pid,$role);
00283 }
00284 if($actid && $rid) {
00285 $am->add_activity_role($actid,$rid);
00286 }
00287 }
00288 }
00289 foreach($data['transitions'] as $tran) {
00290 $am->add_transition($pid,$actids[$tran['from']],$actids[$tran['to']]);
00291 }
00292
00293 foreach ($actids as $name => $actid) {
00294 $am->compile_activity($pid,$actid);
00295 }
00296
00297 $am->build_process_graph($pid);
00298 unset($am);
00299 unset($rm);
00300 $msg = sprintf(tra('Process %s %s imported'),$proc_info['name'],$proc_info['version']);
00301 $this->notify_all(2,$msg);
00302 }
00303
00310
00311 function new_process_version($pId, $minor=true)
00312 {
00313 $oldpid = $pId;
00314 $proc_info = $this->get_process($pId);
00315 $name = $proc_info['name'];
00316 if(!$proc_info) return false;
00317
00318 $version = $this->_new_version($proc_info['version'],$minor);
00319 while($this->getOne("select count(*) from ".GALAXIA_TABLE_PREFIX."processes where name='$name' and version='$version'")) {
00320 $version = $this->_new_version($version,$minor);
00321 }
00322
00323 $proc_info['version'] = $version;
00324 $proc_info['isActive'] = 'n';
00325
00326 $pid = $this->replace_process(0, $proc_info, false);
00327
00328 $am = new ActivityManager($this->db);
00329 $query = "select * from ".GALAXIA_TABLE_PREFIX."activities where pId=$oldpid";
00330 $result = $this->query($query);
00331 $newaid = array();
00332 while($res = $result->fetchRow()) {
00333 $oldaid = $res['activityId'];
00334 $newaid[$oldaid] = $am->replace_activity($pid,0,$res);
00335 }
00336
00337 $query = "select * from ".GALAXIA_TABLE_PREFIX."transitions where pId=$oldpid";
00338 $result = $this->query($query);
00339 while($res = $result->fetchRow()) {
00340 if (empty($newaid[$res['actFromId']]) || empty($newaid[$res['actToId']])) {
00341 continue;
00342 }
00343 $am->add_transition($pid,$newaid[$res['actFromId']],$newaid[$res['actToId']]);
00344 }
00345
00346 $rm = new RoleManager($this->db);
00347 $query = "select * from ".GALAXIA_TABLE_PREFIX."roles where pId=$oldpid";
00348 $result = $this->query($query);
00349 $newrid = array();
00350 while($res = $result->fetchRow()) {
00351 if(!$rm->role_name_exists($pid,$res['name'])) {
00352 $rid=$rm->replace_role($pid,0,$res);
00353 } else {
00354 $rid = $rm->get_role_id($pid,$res['name']);
00355 }
00356 $newrid[$res['roleId']] = $rid;
00357 }
00358
00359 if (count($newrid) > 0) {
00360 $query = "select * from ".GALAXIA_TABLE_PREFIX."user_roles where pId=$oldpid";
00361 $result = $this->query($query);
00362 while($res = $result->fetchRow()) {
00363 if (empty($newrid[$res['roleId']])) {
00364 continue;
00365 }
00366 $rm->map_user_to_role($pid,$res['user'],$newrid[$res['roleId']]);
00367 }
00368 }
00369
00370 if (count($newaid) > 0 && count($newrid ) > 0) {
00371 $query = "select * from ".GALAXIA_TABLE_PREFIX."activity_roles where activityId in (" . join(', ',array_keys($newaid)) . ")";
00372 $result = $this->query($query);
00373 while($res = $result->fetchRow()) {
00374 if (empty($newaid[$res['activityId']]) || empty($newrid[$res['roleId']])) {
00375 continue;
00376 }
00377 $am->add_activity_role($newaid[$res['activityId']],$newrid[$res['roleId']]);
00378 }
00379 }
00380
00381
00382
00383 $oldname = $proc_info['normalized_name'];
00384 $newname = $this->_get_normalized_name($pid);
00385 $this->_rec_copy(GALAXIA_PROCESSES."/$oldname",GALAXIA_PROCESSES."/$newname");
00386
00387
00388 $am->build_process_graph($pid);
00389 return $pid;
00390 }
00391
00398 function process_name_exists($name,$version)
00399 {
00400 $name = addslashes($this->_normalize_name($name,$version));
00401 return $this->getOne("select count(*) from ".GALAXIA_TABLE_PREFIX."processes where normalized_name='$name'");
00402 }
00403
00404
00408 function get_process($pId)
00409 {
00410 $query = "select * from ".GALAXIA_TABLE_PREFIX."processes where pId=$pId";
00411 $result = $this->query($query);
00412 if(!$result->numRows()) return false;
00413 $res = $result->fetchRow();
00414 return $res;
00415 }
00416
00420 function list_processes($offset,$maxRecords,$sort_mode,$find,$where='')
00421 {
00422 $sort_mode = $this->convert_sortmode($sort_mode);
00423 if($find) {
00424 $findesc = '%'.$find.'%';
00425 $mid=" where ((name like ?) or (description like ?))";
00426 $bindvars = array($findesc,$findesc);
00427 } else {
00428 $mid="";
00429 $bindvars = array();
00430 }
00431 if($where) {
00432 if($mid) {
00433 $mid.= " and ($where) ";
00434 } else {
00435 $mid.= " where ($where) ";
00436 }
00437 }
00438 $query = "select * from ".GALAXIA_TABLE_PREFIX."processes $mid order by $sort_mode";
00439 $query_cant = "select count(*) from ".GALAXIA_TABLE_PREFIX."processes $mid";
00440 $result = $this->query($query,$bindvars,$maxRecords,$offset);
00441 $cant = $this->getOne($query_cant,$bindvars);
00442 $ret = Array();
00443 while($res = $result->fetchRow()) {
00444 $ret[] = $res;
00445 }
00446 $retval = Array();
00447 $retval["data"] = $ret;
00448 $retval["cant"] = $cant;
00449 return $retval;
00450 }
00451
00455 function invalidate_process($pid)
00456 {
00457 $query = "update ".GALAXIA_TABLE_PREFIX."processes set isValid='n' where pId=$pid";
00458 $this->query($query);
00459 }
00460
00464 function remove_process($pId)
00465 {
00466 $this->deactivate_process($pId);
00467 $name = $this->_get_normalized_name($pId);
00468 $aM = new ActivityManager($this->db);
00469
00470 $query = "select activityId from ".GALAXIA_TABLE_PREFIX."activities where pId=$pId";
00471 $result = $this->query($query);
00472 while($res = $result->fetchRow()) {
00473 $aM->remove_activity($pId,$res['activityId']);
00474 }
00475
00476
00477 $query = "delete from ".GALAXIA_TABLE_PREFIX."roles where pId=$pId";
00478 $this->query($query);
00479 $query = "delete from ".GALAXIA_TABLE_PREFIX."user_roles where pId=$pId";
00480 $this->query($query);
00481
00482
00483 if (!empty($name) && is_dir(GALAXIA_PROCESSES."/$name")) {
00484 $this->_remove_directory(GALAXIA_PROCESSES."/$name",true);
00485 }
00486 if (GALAXIA_TEMPLATES && !empty($name) && is_dir(GALAXIA_TEMPLATES."/$name")) {
00487 $this->_remove_directory(GALAXIA_TEMPLATES."/$name",true);
00488 }
00489
00490 $query = "delete from ".GALAXIA_TABLE_PREFIX."processes where pId=$pId";
00491 $this->query($query);
00492 $msg = sprintf(tra('Process %s removed'),$name);
00493 $this->notify_all(5,$msg);
00494
00495 return true;
00496 }
00497
00503 function replace_process($pId, $vars, $create = true)
00504 {
00505 $TABLE_NAME = GALAXIA_TABLE_PREFIX."processes";
00506 $now = date("U");
00507 $vars['lastModif']=$now;
00508 $vars['normalized_name'] = $this->_normalize_name($vars['name'],$vars['version']);
00509 foreach($vars as $key=>$value)
00510 {
00511 $vars[$key]=addslashes($value);
00512 }
00513
00514 if($pId) {
00515
00516 $old_proc = $this->get_process($pId);
00517 $first = true;
00518 $query ="update $TABLE_NAME set";
00519 foreach($vars as $key=>$value) {
00520 if(!$first) $query.= ',';
00521 if(!is_numeric($value)||strstr($value,'.')) $value="'".$value."'";
00522 $query.= " $key=$value ";
00523 $first = false;
00524 }
00525 $query .= " where pId=$pId ";
00526 $this->query($query);
00527
00528
00529 $oldname = $old_proc['normalized_name'];
00530 $newname = $vars['normalized_name'];
00531 if ($newname != $oldname) {
00532 rename(GALAXIA_PROCESSES."/$oldname",GALAXIA_PROCESSES."/$newname");
00533 }
00534 $msg = sprintf(tra('Process %s has been updated'),$vars['name']);
00535 $this->notify_all(3,$msg);
00536 } else {
00537 unset($vars['pId']);
00538
00539 $name = $this->_normalize_name($vars['name'],$vars['version']);
00540 $this->_create_directory_structure($name);
00541 $first = true;
00542 $query = "insert into $TABLE_NAME(";
00543 foreach(array_keys($vars) as $key) {
00544 if(!$first) $query.= ',';
00545 $query.= "$key";
00546 $first = false;
00547 }
00548 $query .=") values(";
00549 $first = true;
00550 foreach(array_values($vars) as $value) {
00551 if(!$first) $query.= ',';
00552 if(!is_numeric($value)||strstr($value,'.')) $value="'".$value."'";
00553 $query.= "$value";
00554 $first = false;
00555 }
00556 $query .=")";
00557 $this->query($query);
00558 $pId = $this->getOne("select max(pId) from $TABLE_NAME where lastModif=$now");
00559
00560
00561 if($create) {
00562 $aM= new ActivityManager($this->db);
00563 $vars1 = Array(
00564 'name' => 'start',
00565 'description' => 'default start activity',
00566 'type' => 'start',
00567 'isInteractive' => 'y',
00568 'isAutoRouted' => 'y'
00569 );
00570 $vars2 = Array(
00571 'name' => 'end',
00572 'description' => 'default end activity',
00573 'type' => 'end',
00574 'isInteractive' => 'n',
00575 'isAutoRouted' => 'y'
00576 );
00577
00578 $aM->replace_activity($pId,0,$vars1);
00579 $aM->replace_activity($pId,0,$vars2);
00580 }
00581 $msg = sprintf(tra('Process %s has been created'),$vars['name']);
00582 $this->notify_all(4,$msg);
00583 }
00584
00585 return $pId;
00586 }
00587
00592 function _get_normalized_name($pId)
00593 {
00594 $info = $this->get_process($pId);
00595 return $info['normalized_name'];
00596 }
00597
00602 function _normalize_name($name, $version)
00603 {
00604 $name = $name.'_'.$version;
00605 $name = str_replace(" ","_",$name);
00606 $name = preg_replace("/[^0-9A-Za-z\_]/",'',$name);
00607 return $name;
00608 }
00609
00614 function _new_version($version,$minor=true)
00615 {
00616 $parts = explode('.',$version);
00617 if($minor) {
00618 $parts[count($parts)-1]++;
00619 } else {
00620 $parts[0]++;
00621 for ($i = 1; $i < count($parts); $i++) {
00622 $parts[$i] = 0;
00623 }
00624 }
00625 return implode('.',$parts);
00626 }
00627
00632 function _create_directory_structure($name)
00633 {
00634
00635 mkdir(GALAXIA_PROCESSES."/$name",0770);
00636 mkdir(GALAXIA_PROCESSES."/$name/graph",0770);
00637 mkdir(GALAXIA_PROCESSES."/$name/code",0770);
00638 mkdir(GALAXIA_PROCESSES."/$name/compiled",0770);
00639 mkdir(GALAXIA_PROCESSES."/$name/code/activities",0770);
00640 mkdir(GALAXIA_PROCESSES."/$name/code/templates",0770);
00641 if (GALAXIA_TEMPLATES) {
00642 mkdir(GALAXIA_TEMPLATES."/$name",0770);
00643 }
00644
00645 $fp = fopen(GALAXIA_PROCESSES."/$name/code/shared.php","w");
00646 fwrite($fp,'<'.'?'.'php'."\n".'?'.'>');
00647 fclose($fp);
00648 }
00649
00654 function _remove_directory($dir,$rec=false)
00655 {
00656
00657 if(trim($dir) == '/'|| trim($dir)=='.' || trim($dir)=='templates' || trim($dir)=='templates/') return false;
00658 $h = opendir($dir);
00659 while(($file = readdir($h)) != false) {
00660 if(is_file($dir.'/'.$file)) {
00661 @unlink($dir.'/'.$file);
00662 } else {
00663 if($rec && $file != '.' && $file != '..') {
00664 $this->_remove_directory($dir.'/'.$file, true);
00665 }
00666 }
00667 }
00668 closedir($h);
00669 @rmdir($dir);
00670 @unlink($dir);
00671 }
00672
00673 function _rec_copy($dir1,$dir2)
00674 {
00675 @mkdir($dir2,0777);
00676 $h = opendir($dir1);
00677 while(($file = readdir($h)) !== false) {
00678 if(is_file($dir1.'/'.$file)) {
00679 copy($dir1.'/'.$file,$dir2.'/'.$file);
00680 } else {
00681 if($file != '.' && $file != '..') {
00682 $this->_rec_copy($dir1.'/'.$file, $dir2.'/'.$file);
00683 }
00684 }
00685 }
00686 closedir($h);
00687 }
00688
00689 function _start_element_handler($parser,$element,$attribs)
00690 {
00691 $aux=Array('name'=>$element,
00692 'data'=>'',
00693 'parent' => $this->current,
00694 'children'=>Array());
00695 $i = count($this->tree);
00696 $this->tree[$i] = $aux;
00697
00698 $this->tree[$this->current]['children'][]=$i;
00699 $this->current=$i;
00700 }
00701
00702
00703 function _end_element_handler($parser,$element)
00704 {
00705
00706 $this->tree[$this->current]['data']=$this->buffer;
00707 $this->buffer='';
00708 $this->current=$this->tree[$this->current]['parent'];
00709 }
00710
00711
00712 function _data_handler($parser,$data)
00713 {
00714 $this->buffer.=$data;
00715 }
00716
00717 }
00718
00719
00720 ?>