source: branches/2.2/workflow/inc/local/classes/class.wf_instance.php @ 3167

Revision 3167, 17.9 KB checked in by viani, 14 years ago (diff)

Ticket #1135 - Merged r1990:3166 from /trunk/workflow into /branches/2.2/workflow

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::getInstance('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::getInstance('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        */
246        public function getAll($activities = null)
247        {
248                return $this->getIdle(0, $activities);
249        }
250
251        /**
252        * This method gets all children instances of the given instance.
253        * If there is no parameter, it gets the children instances of the current instance
254        * @param int $instanceID Dad instance's identification.
255        * @return array Array with the children instances, or false
256        * @access public
257        */
258        public function getChildren($instanceID = null)
259        {
260                $output = array();
261                if (is_null($instanceID))
262                        $instanceID = $GLOBALS['workflow']['wf_runtime']->instance_id;
263
264                /* check instanceID */
265                if (!$this->checkInstanceAccess($instanceID))
266                        return $output;
267
268                /* build the SQL query */
269                $query = "
270                        SELECT
271                                i.wf_instance_id AS wf_instance_id,
272                                ia.wf_activity_id AS wf_activity_id,
273                                i.wf_started AS wf_started,
274                                i.wf_name AS wf_name,
275                                i.wf_status AS wf_status,
276                                ia.wf_user AS wf_user,
277                                ir.wf_parent_lock AS wf_parent_lock
278                        FROM
279                            egw_wf_interinstance_relations as ir
280                        LEFT JOIN
281                            egw_wf_instances as i
282                        ON
283                            i.wf_instance_id = ir.wf_child_instance_id
284                        LEFT JOIN
285                            egw_wf_instance_activities as ia
286                        ON
287                            i.wf_instance_id = ia.wf_instance_id
288                        WHERE
289                            ir.wf_parent_instance_id = ?";
290
291                $result = $this->db->query($query, array($instanceID));
292                $output = $result->GetArray(-1);
293
294                return $output;
295        }
296
297        /**
298        * Busca as propriedades de uma instância (do mesmo processo).
299        * @param int $instanceID O ID da instância.
300        * @return mixed Uma array contento as propriedades da instância (no formato "nome_da_propriedade" => "valor"). Ou false em caso de erro.
301        * @access public
302        */
303        public function getProperties($instanceID)
304        {
305                /* check instanceID */
306                if (!$this->checkInstanceAccess($instanceID))
307                        return false;
308
309                /* load the properties of the instance object */
310                return $this->getInstanceObject($instanceID)->properties;
311        }
312
313        /**
314        * Define uma propriedade de uma instância.
315        * @param int $instanceID O ID da instância.
316        * @return bool true caso a propriedade tenha sido alterada com sucesso
317        * @access public
318        */
319        public function setProperty($instanceID, $propertyName, $propertyValue)
320        {
321                /* check instanceID */
322                if (!$this->checkInstanceAccess($instanceID))
323                        return false;
324
325                /* load the instance object */
326                $instance = $this->getInstanceObject($instanceID);
327
328                /* set the property */
329                $output = $instance->set($propertyName, $propertyValue);
330                $output = $output && $instance->sync();
331
332                return $output;
333        }
334
335        /**
336        * Busca as instância de usuários de acordo com alguns critérios
337        * @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)
338        * @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)
339        * @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)
340        * @return array As instâncias que satisfazem o critério de seleção.
341        * @access public
342        */
343        public function getByUser($users, $activities = null, $status = null)
344        {
345                /* check for the supplied users/roles */
346                if (empty($users))
347                        return array();
348                if (!is_array($users))
349                        $users = array($users);
350                foreach ($users as &$user)
351                {
352                        if (!eregi('^[p]{0,1}[0-9]+$', "$user"))
353                                trigger_error('wf_engine::getUserInstances: O usuário/perfil "' . $user . '" é inválido', E_USER_ERROR);
354                        $user = "'{$user}'";
355                }
356
357                /* check for activity restriction */
358                $restrictToActivities = !is_null($activities);
359                if (!is_array($activities))
360                        $activities = array((int) $activities);
361                array_walk($activities, create_function('&$a', '$a = (int) $a;'));
362
363                /* check for status restriction */
364                $statusPossibleValues = array('completed', 'active', 'aborted', 'exception');
365                $restrictToStatus = !is_null($status);
366                if (is_string($status))
367                        $status = array($status);
368                /* check if the supplied status are valid */
369                if ($restrictToStatus)
370                {
371                        array_walk($status, create_function('&$a', '$a = strtolower($a);'));
372                        foreach ($status as $currentStatus)
373                                if (!in_array($currentStatus, $statusPossibleValues))
374                                        trigger_error('wf_engine::getUserInstances: O status "' . $currentStatus . '" é inválido', E_USER_ERROR);
375                }
376
377                /* build the SQL query */
378                $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 ";
379                $query .= "FROM egw_wf_instance_activities ia, egw_wf_instances i ";
380                $query .= "WHERE (ia.wf_instance_id = i.wf_instance_id) AND (i.wf_p_id = ?) AND (ia.wf_user IN (" . implode(', ', $users) . "))";
381                $values = array($this->processID);
382
383                if ($restrictToActivities)
384                {
385                        $query .= ' AND (ia.wf_activity_id = ANY (?))';
386                        $values[] = '{' . implode(', ', $activities) . '}';
387                }
388
389                if ($restrictToStatus)
390                {
391                        $aux = ' AND (i.wf_status IN (';
392                        foreach($status as $id){
393                                $values[] = $id;
394                                $query .= $aux.' ?';
395                                $aux = ', ';
396                        }
397                        $query .= ' ))';
398                }
399
400                $resultSet = $this->db->query($query, $values);
401
402                /* fetch and return the results */
403                return $resultSet->GetArray(-1);
404        }
405
406        /**
407        * Busca todas as instâncias que possuem esse nome (identificador).
408        * @param string $name O nome da instância que se quer encontrar.
409        * @return array As instâncias que satisfazem o critério de seleção.
410        * @access public
411        */
412        public function getByName($name)
413        {
414                /* build the SQL query */
415                $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 ';
416                $query .= 'FROM egw_wf_instances i LEFT JOIN egw_wf_instance_activities ia ON (ia.wf_instance_id = i.wf_instance_id)';
417                $query .= 'WHERE (i.wf_p_id = ?) AND (UPPER(i.wf_name) = UPPER(?))';
418
419                $resultSet = $this->db->query($query, array($this->processID, $name));
420                return $resultSet->GetArray();
421        }
422
423        /**
424        * Verifica se um dado usuário tem acesso a uma instância
425        * @param int $userID O ID do usuário que se quer verificar
426        * @param int $instanceID O ID da instância
427        * @param int $activityID O ID da atividade onde a instância está
428        * @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
429        * @return bool true se o usuário tiver acesso à instância (levando em consideração $writeAccess) ou false caso contrário
430        * @access public
431        */
432        public function checkUserAccess($userID, $instanceID, $activityID, $writeAccess = true)
433        {
434                /* only integers are allowed */
435                $userID = (int) $userID;
436                $instanceID = (int) $instanceID;
437                $activityID = (int) $activityID;
438
439                /* load the required instance (for the required user) */
440                $GUI = &Factory::newInstance('GUI');
441                $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);
442                $userInstance = $userInstance['data'];
443
444                /* if no instance is found, the user does not have access to it */
445                if (empty($userInstance))
446                        return false;
447
448                /* if no write access is required, then the user have access to the instance */
449                if (!$writeAccess)
450                        return true;
451
452                /* write access is required, check for it */
453                return ($userInstance['wf_readonly'] == 0);
454        }
455
456        /**
457        * Define o usuário de uma instância (em uma atividade)
458        * @param int $instanceID O ID da instância.
459        * @param int $activityID O ID da atividade.
460        * @param int $userID O ID do usuário.
461        * @return boolean true se foi possível definir o usuário da instância ou false caso contrário.
462        * @access public
463        */
464        public function setUser($instanceID, $activityID, $userID)
465        {
466                /* check instanceID and activityID */
467                if (!$this->checkInstanceAccess($instanceID, $activityID))
468                        return false;
469
470                if ($userID !== '*')
471                {
472                        $wfRole = Factory::getInstance('wf_role');
473                        $engine = Factory::getInstance('wf_engine');
474                        /* get information about the activity */
475                        if (($activityInfo = $engine->getActivityInformationByID($activityID)) === false)
476                                return false;
477
478                        /* load the possible roles of the activity */
479                        $possibleRoles = $wfRole->getActivityRoles($activityInfo['name']);
480                        if (substr($userID, 0, 1) == 'p')
481                        {
482                                /* the instance is being set to a role */
483                                /* check if the role is valid */
484                                $roleID = (int) substr($userID, 1);
485                                $userID = 'p' . $roleID;
486                                $validRole = false;
487                                foreach ($possibleRoles as $possibleRole)
488                                {
489                                        if ($roleID == $possibleRole['id'])
490                                        {
491                                                $validRole = true;
492                                                break;
493                                        }
494                                }
495                                if (!$validRole)
496                                        return false;
497                        }
498                        else
499                        {
500                                /* the instance is being set to a user */
501                                /* check if the $userID is a number */
502                                if (!is_numeric($userID))
503                                        return false;
504
505                                /* check if the user is valid */
506                                $userID = (int) $userID;
507                                $validUser = false;
508                                foreach ($possibleRoles as $possibleRole)
509                                {
510                                        if ($wfRole->checkUserInRole($userID, $possibleRole['name']))
511                                        {
512                                                $validUser = true;
513                                                break;
514                                        }
515                                }
516                                if (!$validUser)
517                                        return false;
518                        }
519                }
520
521                $query = 'UPDATE egw_wf_instance_activities SET wf_user = ? WHERE (wf_instance_id = ?) AND (wf_activity_id = ?)';
522                $this->db->execute($query, array($userID, $instanceID, $activityID));
523
524                return true;
525        }
526
527        /**
528        * Define o perfil que poderá acessar uma instância (em uma atividade)
529        * @param int $instanceID O ID da instância.
530        * @param int $activityID O ID da atividade.
531        * @param string $roleName O nome do perfil.
532        * @return boolean true se foi possível definir o perfil da instância ou false caso contrário.
533        * @access public
534        */
535        public function setRole($instanceID, $activityID, $roleName)
536        {
537                /* check instanceID and activityID */
538                if (!$this->checkInstanceAccess($instanceID, $activityID))
539                        return false;
540
541                /* try to get the role id */
542                $wfRole = Factory::getInstance('wf_role');
543                if (($roleID = $wfRole->getRoleIdByName($roleName)) === false)
544                        return false;
545
546                return $this->setUser($instanceID, $activityID, 'p' . $roleID);
547        }
548}
549?>
Note: See TracBrowser for help on using the repository browser.