source: sandbox/workflow/trunk/inc/local/classes/class.wf_instance.php @ 2372

Revision 2372, 18.1 KB checked in by pedroerp, 14 years ago (diff)

Ticket #609 - Merged 2197:2356 /sandbox/workflow/branches/609/ em /sandbox/workflow/trunk.

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