source: branches/2.5/workflow/inc/local/classes/class.wf_instance.php @ 8232

Revision 8232, 21.6 KB checked in by douglas, 11 years ago (diff)

Ticket #0000 - Copiadas as alterações do Trunk. Versão final 2.5.1.

Line 
1<?php
2/**************************************************************************\
3* eGroupWare                                                               *
4* http://www.egroupware.org                                                *
5* --------------------------------------------                             *
6*  This program is free software; you can redistribute it and/or modify it *
7*  under the terms of the GNU General Public License as published by the   *
8*  Free Software Foundation; either version 2 of the License, or (at your  *
9*  option) any later version.                                              *
10\**************************************************************************/
11
12/**
13* Provê métodos que acessam informações relacionadas às instâncias.
14* @author Sidnei Augusto Drovetto Junior - drovetto@gmail.com
15* @version 1.0
16* @license http://www.gnu.org/copyleft/gpl.html GPL
17* @package Workflow
18* @subpackage local
19*/
20class wf_instance
21{
22        /**
23        * @var object $db objeto do banco de dados
24        * @access private
25        */
26        private $db;
27
28        /**
29        * @var int $processID o ID do processo onde a classe está sendo utilizada
30        * @access private
31        */
32        private $processID;
33
34        /**
35        * Verifica se um dado processo equivale àquele que está sendo executado.
36        * @param int $processID O ID do processo.
37        * @return bool true caso sejam o mesmo processo ou, false caso contrário.
38        * @access public
39        */
40        private function checkProcessAccess($processID)
41        {
42                $processID = (int) $processID;
43                return ($processID === $this->processID);
44        }
45
46        /**
47        * Verifica se uma instância pertence ao processo que está sendo executado.
48        * @param int instanceID O ID da instância.
49        * @return bool true caso a instância pertença ao processo que está sendo executado ou, false caso contrário.
50        * @access public
51        */
52        private function checkInstanceAccess($instanceID, $activityID = null)
53        {
54                $instance = $this->getInstanceObject($instanceID);
55                if ($instance === false)
56                        return false;
57                if (!is_null($activityID))
58                {
59                        $activityFound = false;
60                        foreach ($instance->activities as $activity)
61                                if (($activityFound = ($activityID == $activity['wf_activity_id'])))
62                                        break;
63
64                        if ($activityFound == false)
65                                return false;
66                }
67                return $this->checkProcessAccess($instance->pId);
68        }
69
70        /**
71        * Pega o objeto de uma instância.
72        * @param int instanceID O ID da instância.
73        * @return mixed object caso a instância seja encontrada ou false caso contrário.
74        * @access public
75        */
76        private function getInstanceObject($instanceID)
77        {
78                $instanceID = (int) $instanceID;
79                $instance = Factory::newInstance('workflow_instance');
80                if (!$instance->getInstance($instanceID))
81                        return false;
82                else
83                        return $instance;
84        }
85
86        /**
87        * Construtor do wf_instances.
88        * @return object
89        * @access public
90        */
91        public function wf_instance()
92        {
93                /* load the DB */
94                $this->db = &Factory::getInstance('WorkflowObjects')->getDBGalaxia()->Link_ID;
95
96                /* load the process ID from the runtime */
97                if (!is_null($GLOBALS['workflow']['wf_runtime']->activity))
98                        $this->processID = (int) $GLOBALS['workflow']['wf_runtime']->activity->getProcessId();
99                /* if a job is running the process, then load the processID specified by the job */
100                if (isset($GLOBALS['workflow']['job']))
101                        $this->processID = (int) $GLOBALS['workflow']['job']['processID'];
102        }
103
104        /**
105        * Dá seqüência no fluxo de uma instância (simula ação do usuário).
106        * @param int $activityID O ID da atividade da instância.
107        * @param int $instanceID O ID da instância.
108        * @return bool true caso a instância tenha sido continuada e false caso contrário.
109        * @access public
110        */
111        public function continueInstance($activityID, $instanceID)
112        {
113                /* check instanceID */
114                if (!$this->checkInstanceAccess($instanceID, $activityID))
115                        return false;
116
117                /* load the instance object */
118                $instance = $this->getInstanceObject($instanceID);
119
120                $runActivity = Factory::newInstance('run_activity');
121
122                ob_start();
123                $output = $runActivity->go($activityID, $instanceID, true);
124                ob_end_clean();
125
126                return ($output !== false);
127        }
128
129        /**
130        * Aborta uma instância
131        * @param int $instanceID O ID da instância.
132        * @return boolean true se foi possível abortar a instância e false caso contrário.
133        * @access public
134        */
135        public function abort($instanceID)
136        {
137                /* check instanceID */
138                if (!$this->checkInstanceAccess($instanceID))
139                        return false;
140
141                /* load the instance object */
142                $instance = $this->getInstanceObject($instanceID);
143
144                /* abort the instance */
145                return $instance->abort();
146        }
147
148        /**
149        * Define o nome (identificador) de uma instância
150        * @param int $instanceID O ID da instância.
151        * @param string $name O novo nome da instância.
152        * @return boolean true se foi possível mudar o nome da instância e false caso contrário.
153        * @access public
154        */
155        public function setName($instanceID, $name)
156        {
157                /* check instanceID */
158                if (!$this->checkInstanceAccess($instanceID))
159                        return false;
160
161                /* load the instance object */
162                $instance = $this->getInstanceObject($instanceID);
163
164                /* set the name */
165                $output = $instance->setName($name);
166                $output = $output && $instance->sync();
167
168                return $output;
169        }
170
171        /**
172        * Define a prioridade de uma instância
173        * @param int $instanceID O ID da instância.
174        * @param int $priority A nova prioridade da instância
175        * @return boolean true se foi possível mudar a prioridade da instância e false caso contrário.
176        * @access public
177        */
178        public function setPriority($instanceID, $priority)
179        {
180                /* check instanceID */
181                if (!$this->checkInstanceAccess($instanceID))
182                        return false;
183
184                /* load the instance object */
185                $instance = $this->getInstanceObject($instanceID);
186
187                /* ensure the instance priority range */
188                $priority = max(min((int) $priority, 4), 0);
189
190                /* set the new priority */
191                $output = $instance->setPriority($priority);
192                $output = $output && $instance->sync();
193                return $output;
194        }
195
196        /**
197        * Busca instâncias ativas que estão "abandonadas".
198        * @param int $numberOfDays O tempo (em dias) em que a instância está abandonada.
199        * @param array $activities Uma lista de atividades das quais se quer as instâncias abandonadas (também pode ser um valor inteiro).
200        * @return array As instâncias que satisfazem o critério de seleção.
201        * @access public
202        */
203        public function getIdle($numberOfDays, $activities = null)
204        {
205                /* prepare some variables */
206                $output = array();
207                $restrictToActivities = !is_null($activities);
208                if (is_numeric($activities))
209                        $activities = array((int) $activities);
210
211                if (is_numeric($numberOfDays))
212                        $numberOfDays = (int) $numberOfDays;
213                else
214                        return $output;
215
216                /* restrict the range and get the threshold date (in UNIX ERA format) */
217                $numberOfDays = max(0, $numberOfDays);
218                $threshold = time() - ($numberOfDays * 24 * 60 * 60);
219
220                /* build the SQL query */
221                $query = 'SELECT ia.wf_instance_id AS wf_instance_id, ia.wf_activity_id AS wf_activity_id, ia.wf_started AS wf_started, i.wf_name AS wf_name, i.wf_status AS wf_status, ia.wf_user AS wf_user, i.wf_priority AS wf_priority ';
222                $query .= 'FROM egw_wf_instance_activities ia, egw_wf_instances i ';
223                $query .= 'WHERE (ia.wf_instance_id = i.wf_instance_id) AND (i.wf_p_id = ?) AND (ia.wf_started < ?)';
224                $resultSet = $this->db->query($query, array($this->processID, $threshold));
225
226                /* fetch the results */
227                while ($row = $resultSet->fetchRow())
228                {
229                        /* if required, restrict to specific activities */
230                        if ($restrictToActivities)
231                                if (!in_array($row['wf_activity_id'], $activities))
232                                        continue;
233
234                        $output[] = $row;
235                }
236
237                return $output;
238        }
239
240        /**
241        * Busca todas as instâncias ativas.
242        * @param array $activities Uma lista de atividades das quais se quer as instâncias (também pode ser um valor inteiro).
243        * @return array As instâncias que satisfazem o critério de seleção.
244        * @access public
245        * @deprecated 2.2.000
246        */
247        public function getAll($activities = null)
248        {
249                wf_warn_deprecated_method('wf_instances', 'getAllActive');
250                return $this->getIdle(0, $activities);
251        }
252
253        /**
254        * Search and return all active instances.
255        * @param array $activities A list of activities codes to restrict instances from (may also be a single integer code).
256        * @return array The instaces which match the search criteria.
257        * @access public
258        */
259        public function getAllActive($activities = null)
260        {
261                return $this->getIdle(0, $activities);
262        }
263
264        /**
265        * Retrieve all completed instances.
266        * @return array All completed instances from current process. Be careful this may be a long array.
267        * @access public
268        */
269        public function getAllCompleted()
270        {
271                $output = array();
272
273                // Build the SQL query
274                // Select all instances from the process that has a final date
275                $query = 'SELECT i.wf_instance_id, i.wf_started, i.wf_ended, i.wf_name, i.wf_status, i.wf_priority ';
276                $query .= 'FROM egw_wf_instances i ';
277                $query .= 'WHERE (i.wf_p_id = ?) AND (i.wf_ended > 0)';
278                $resultSet = $this->db->query($query, array($this->processID));
279
280                /* fetch the results */
281                while ($row = $resultSet->fetchRow())
282                {
283                        $output[] = $row;
284                }
285
286                return $output;
287        }
288
289        /**
290        * This method gets all children instances of the given instance.
291        * If there is no parameter, it gets the children instances of the current instance
292        * @param int $instanceID Dad instance's identification.
293        * @return array Array with the children instances, or false
294        * @access public
295        */
296        public function getChildren($instanceID = null)
297        {
298                $output = array();
299                if (is_null($instanceID))
300                        $instanceID = $GLOBALS['workflow']['wf_runtime']->instance_id;
301
302                /* check instanceID */
303                if (!$this->checkInstanceAccess($instanceID))
304                        return $output;
305
306                /* build the SQL query */
307                $query = "
308                        SELECT
309                                i.wf_instance_id AS wf_instance_id,
310                                ia.wf_activity_id AS wf_activity_id,
311                                i.wf_started AS wf_started,
312                                i.wf_name AS wf_name,
313                                i.wf_status AS wf_status,
314                                ia.wf_user AS wf_user,
315                                ir.wf_parent_lock AS wf_parent_lock
316                        FROM
317                            egw_wf_interinstance_relations as ir
318                        LEFT JOIN
319                            egw_wf_instances as i
320                        ON
321                            i.wf_instance_id = ir.wf_child_instance_id
322                        LEFT JOIN
323                            egw_wf_instance_activities as ia
324                        ON
325                            i.wf_instance_id = ia.wf_instance_id
326                        WHERE
327                            ir.wf_parent_instance_id = ?";
328
329                $result = $this->db->query($query, array($instanceID));
330                $output = $result->GetArray(-1);
331
332                return $output;
333        }
334
335        /**
336        * Busca as propriedades de uma instância (do mesmo processo).
337        * @param int $instanceID O ID da instância.
338        * @return mixed Uma array contento as propriedades da instância (no formato "nome_da_propriedade" => "valor"). Ou false em caso de erro.
339        * @access public
340        */
341        public function getProperties($instanceID)
342        {
343                /* check instanceID */
344                if (!$this->checkInstanceAccess($instanceID))
345                        return false;
346
347                /* load the properties of the instance object */
348                return $this->getInstanceObject($instanceID)->properties;
349        }
350
351        /**
352        * Define uma propriedade de uma instância.
353        * @param int $instanceID O ID da instância.
354        * @return bool true caso a propriedade tenha sido alterada com sucesso
355        * @access public
356        */
357        public function setProperty($instanceID, $propertyName, $propertyValue)
358        {
359                /* check instanceID */
360                if (!$this->checkInstanceAccess($instanceID))
361                        return false;
362
363                /* load the instance object */
364                $instance = $this->getInstanceObject($instanceID);
365
366                /* set the property */
367                $output = $instance->set($propertyName, $propertyValue);
368                $output = $output && $instance->sync();
369
370                return $output;
371        }
372
373        /**
374        * Busca as instância de usuários de acordo com alguns critérios
375        * @param mixed $users Um array com IDs de usuários ou perfis (no caso de perfis, deve-se prefixar seu ID com o caractere 'p'). Também pode possuir um único ID (seja de usuário ou de perfil)
376        * @param mixed $activities Um array com IDs de atividades das se quer as instâncias. Também pode ser um inteiro, representando um único ID. Caso possua valor null, o resultado não é filtrado de acordo com as atividades (parâmetro opcional)
377        * @param mixed $status Um array com os status requeridos (para filtrar as instâncias). Também pode ser uma string, representando um único status. Caso possua valor null, o resultado não é filtrado de acordo com o status. Os status podem ser: completed, active, aborted e exception (parâmetro opcional)
378        * @return array As instâncias que satisfazem o critério de seleção.
379        * @access public
380        */
381        public function getByUser($users, $activities = null, $status = null)
382        {
383                /* check for the supplied users/roles */
384                if (empty($users))
385                        return array();
386                if (!is_array($users))
387                        $users = array($users);
388                foreach ($users as &$user)
389                {
390                        if (!preg_match('/^[p]{0,1}[0-9]+$/i', "$user"))
391                                trigger_error('wf_engine::getUserInstances: O usuário/perfil "' . $user . '" é inválido', E_USER_ERROR);
392                        $user = "'{$user}'";
393                }
394
395                /* check for activity restriction */
396                $restrictToActivities = !is_null($activities);
397                if (!is_array($activities))
398                        $activities = array((int) $activities);
399                array_walk($activities, create_function('&$a', '$a = (int) $a;'));
400
401                /* check for status restriction */
402                $statusPossibleValues = array('completed', 'active', 'aborted', 'exception');
403                $restrictToStatus = !is_null($status);
404                if (is_string($status))
405                        $status = array($status);
406                /* check if the supplied status are valid */
407                if ($restrictToStatus)
408                {
409                        array_walk($status, create_function('&$a', '$a = strtolower($a);'));
410                        foreach ($status as $currentStatus)
411                                if (!in_array($currentStatus, $statusPossibleValues))
412                                        trigger_error('wf_engine::getUserInstances: O status "' . $currentStatus . '" é inválido', E_USER_ERROR);
413                }
414
415                /* build the SQL query */
416                $query = "SELECT ia.wf_instance_id AS wf_instance_id, ia.wf_activity_id AS wf_activity_id, ia.wf_started AS wf_started, i.wf_name AS wf_name, i.wf_status AS wf_status, ia.wf_user AS wf_user, i.wf_priority AS wf_priority ";
417                $query .= "FROM egw_wf_instance_activities ia, egw_wf_instances i ";
418                $query .= "WHERE (ia.wf_instance_id = i.wf_instance_id) AND (i.wf_p_id = ?) AND (ia.wf_user IN (" . implode(', ', $users) . "))";
419                $values = array($this->processID);
420
421                if ($restrictToActivities)
422                {
423                        $query .= ' AND (ia.wf_activity_id = ANY (?))';
424                        $values[] = '{' . implode(', ', $activities) . '}';
425                }
426
427                if ($restrictToStatus)
428                {
429                        $aux = ' AND (i.wf_status IN (';
430                        foreach($status as $id){
431                                $values[] = $id;
432                                $query .= $aux.' ?';
433                                $aux = ', ';
434                        }
435                        $query .= ' ))';
436                }
437
438                $resultSet = $this->db->query($query, $values);
439
440                /* fetch and return the results */
441                return $resultSet->GetArray(-1);
442        }
443
444        /**
445        * Busca uma instância pelo id
446        * @param int $wf_instance_id O id da instância
447        * @return array As instâncias que satisfazem o critério de seleção.
448        * @access public
449        */
450        public function getById($wf_instance_id)
451        {
452                /* build the SQL query */
453                $query = 'SELECT i.wf_instance_id AS wf_instance_id, ia.wf_activity_id AS wf_activity_id, ia.wf_started AS wf_started, i.wf_name AS wf_name, i.wf_status AS wf_status, ia.wf_user AS wf_user, i.wf_priority AS wf_priority ';
454                $query .= 'FROM egw_wf_instances i LEFT JOIN egw_wf_instance_activities ia ON (ia.wf_instance_id = i.wf_instance_id)';
455                $query .= 'WHERE (i.wf_p_id = ?) AND i.wf_instance_id = ?';
456
457                $resultSet = $this->db->query($query, array($this->processID, intval($wf_instance_id)));
458               
459                return $resultSet->GetArray();
460        }
461
462        /**
463        * Busca todas as instâncias que possuem esse nome (identificador).
464        * @param string $name O nome da instância que se quer encontrar.
465        * @return array As instâncias que satisfazem o critério de seleção.
466        * @access public
467        */
468        public function getByName($name)
469        {
470                /* build the SQL query */
471                $query = 'SELECT i.wf_instance_id AS wf_instance_id, ia.wf_activity_id AS wf_activity_id, ia.wf_started AS wf_started, i.wf_name AS wf_name, i.wf_status AS wf_status, ia.wf_user AS wf_user, i.wf_priority AS wf_priority ';
472                $query .= 'FROM egw_wf_instances i LEFT JOIN egw_wf_instance_activities ia ON (ia.wf_instance_id = i.wf_instance_id)';
473                $query .= 'WHERE (i.wf_p_id = ?) AND (UPPER(i.wf_name) = UPPER(?))';
474
475                $resultSet = $this->db->query($query, array($this->processID, $name));
476                return $resultSet->GetArray();
477        }
478
479        /**
480        * Busca todas as instâncias que possuem um trecho do nome (identificador).
481        * @param string $name O trecho do nome da instância que se quer encontrar.
482        * @return array As instâncias que satisfazem o critério de seleção.
483        * @access public
484        */
485        public function getLikeName($name)
486        {
487                /* build the SQL query */
488                $query = 'SELECT i.wf_instance_id AS wf_instance_id, ia.wf_activity_id AS wf_activity_id, ia.wf_started AS wf_started, i.wf_name AS wf_name, i.wf_status AS wf_status, ia.wf_user AS wf_user, i.wf_priority AS wf_priority ';
489                $query .= 'FROM egw_wf_instances i LEFT JOIN egw_wf_instance_activities ia ON (ia.wf_instance_id = i.wf_instance_id)';
490                $query .= "WHERE (i.wf_p_id = ?) AND i.wf_name ILIKE '%$name%'";
491
492                $resultSet = $this->db->query($query, array($this->processID));
493
494                return $resultSet->GetArray();
495        }
496
497        /**
498        * Verifica se um dado usuário tem acesso a uma instância
499        * @param int $userID O ID do usuário que se quer verificar
500        * @param int $instanceID O ID da instância
501        * @param int $activityID O ID da atividade onde a instância está
502        * @param bool $writeAccess Se true, indica que é necessário que o usuário tenha acesso para modificar a instância (dar seqüência ao fluxo). Se false, não será verificado se o usuário tem permissão de escrita na instância
503        * @return bool true se o usuário tiver acesso à instância (levando em consideração $writeAccess) ou false caso contrário
504        * @access public
505        */
506        public function checkUserAccess($userID, $instanceID, $activityID, $writeAccess = true)
507        {
508                /* only integers are allowed */
509                $userID = (int) $userID;
510                $instanceID = (int) $instanceID;
511                $activityID = (int) $activityID;
512
513                /* load the required instance (for the required user) */
514                $GUI = &Factory::newInstance('GUI');
515                $userInstance = $GUI->gui_list_user_instances($userID, 0, -1, '', '', "(ga.wf_is_interactive = 'y') AND (gia.wf_activity_id = {$activityID}) AND (gia.wf_instance_id = {$instanceID})", false, $this->processID, true, false, true, false, false, false);
516                $userInstance = $userInstance['data'];
517
518                /* if no instance is found, the user does not have access to it */
519                if (empty($userInstance))
520                        return false;
521
522                /* if no write access is required, then the user have access to the instance */
523                if (!$writeAccess)
524                        return true;
525
526                /* write access is required, check for it */
527                return ($userInstance['wf_readonly'] == 0);
528        }
529
530        /**
531        * Define o usuário de uma instância (em uma atividade)
532        * @param int $instanceID O ID da instância.
533        * @param int $activityID O ID da atividade.
534        * @param int $userID O ID do usuário.
535        * @return boolean true se foi possível definir o usuário da instância ou false caso contrário.
536        * @access public
537        */
538        public function setUser($instanceID, $activityID, $userID)
539        {
540                /* check instanceID and activityID */
541                if (!$this->checkInstanceAccess($instanceID, $activityID))
542                        return false;
543
544                if ($userID !== '*')
545                {
546                        $wfRole = Factory::getInstance('wf_role');
547                        $engine = Factory::getInstance('wf_engine');
548                        /* get information about the activity */
549                        if (($activityInfo = $engine->getActivityInformationByID($activityID)) === false)
550                                return false;
551
552                        /* load the possible roles of the activity */
553                        $possibleRoles = $wfRole->getActivityRoles($activityInfo['name']);
554                        if (substr($userID, 0, 1) == 'p')
555                        {
556                                /* the instance is being set to a role */
557                                /* check if the role is valid */
558                                $roleID = (int) substr($userID, 1);
559                                $userID = 'p' . $roleID;
560                                $validRole = false;
561                                foreach ($possibleRoles as $possibleRole)
562                                {
563                                        if ($roleID == $possibleRole['id'])
564                                        {
565                                                $validRole = true;
566                                                break;
567                                        }
568                                }
569                                if (!$validRole)
570                                        return false;
571                        }
572                        else
573                        {
574                                /* the instance is being set to a user */
575                                /* check if the $userID is a number */
576                                if (!is_numeric($userID))
577                                        return false;
578
579                                /* check if the user is valid */
580                                $userID = (int) $userID;
581                                $validUser = false;
582                                foreach ($possibleRoles as $possibleRole)
583                                {
584                                        if ($wfRole->checkUserInRole($userID, $possibleRole['name']))
585                                        {
586                                                $validUser = true;
587                                                break;
588                                        }
589                                }
590                                if (!$validUser)
591                                        return false;
592                        }
593                }
594
595                $query = 'UPDATE egw_wf_instance_activities SET wf_user = ? WHERE (wf_instance_id = ?) AND (wf_activity_id = ?)';
596                $this->db->execute($query, array($userID, $instanceID, $activityID));
597
598                return true;
599        }
600
601        /**
602        * Define o perfil que poderá acessar uma instância (em uma atividade)
603        * @param int $instanceID O ID da instância.
604        * @param int $activityID O ID da atividade.
605        * @param string $roleName O nome do perfil.
606        * @return boolean true se foi possível definir o perfil da instância ou false caso contrário.
607        * @access public
608        */
609        public function setRole($instanceID, $activityID, $roleName)
610        {
611                /* check instanceID and activityID */
612                if (!$this->checkInstanceAccess($instanceID, $activityID))
613                        return false;
614
615                /* try to get the role id */
616                $wfRole = Factory::getInstance('wf_role');
617                if (($roleID = $wfRole->getRoleIdByName($roleName)) === false)
618                        return false;
619
620                return $this->setUser($instanceID, $activityID, 'p' . $roleID);
621        }
622
623        /**
624        * Altera o wf_name das instâncias, fazendo o replace no nome da categoria de serviço.
625        * Método chamado quando é alterada a categoria de um serviço e existem ocorrências atrelados a esse serviço.
626        * @param int | array $instanceID se for um array, concatena os instances ids
627        * @param string @currentServiceName Nome da categoria de serviço atual
628        * @param string @newServiceName Nome da nova categoria de serviço
629        * @return resultSet em caso de sucesso ou false
630        * @access public
631        */
632        public function updateReplaceName($instanceID, $currentServiceName, $newServiceName)
633        {
634                $success = true;
635
636                // Se for array, faz implode concatenando os ids
637                if (is_array($instanceID))
638                {
639                        $instanceID = implode(',', $instanceID);
640                }
641
642                $query = "UPDATE egw_wf_instances SET wf_name = REPLACE(wf_name, '" . $currentServiceName . "', '" . $newServiceName . "') WHERE wf_instance_id IN (" . $instanceID . ")";
643                $success = $this->db->execute($query);
644
645                return $success;
646        }
647}
648?>
Note: See TracBrowser for help on using the repository browser.