source: trunk/workflow/inc/class.so_move_instances.inc.php @ 795

Revision 795, 12.5 KB checked in by viani, 15 years ago (diff)

Ticket #488 - Inclusão do módulo workflow no ramo trunk do repositório Expresso.

Line 
1<?php
2
3/**************************************************************************\
4* eGroupWare                                                               *
5* http://www.egroupware.org                                                *
6* --------------------------------------------                             *
7*  This program is free software; you can redistribute it and/or modify it *
8*  under the terms of the GNU General Public License as published by the   *
9*  Free Software Foundation; either version 2 of the License, or (at your  *
10*  option) any later version.                                              *
11\**************************************************************************/
12
13require_once(GALAXIA_LIBRARY . SEP . 'src' . SEP . 'ProcessManager' . SEP . 'ProcessManager.php');
14require_once(GALAXIA_LIBRARY . SEP . 'src' . SEP . 'ProcessManager' . SEP . 'ActivityManager.php');
15
16/**
17 * Camada Model para Mover Instâncias.
18 * @package Workflow
19 * @author Sidnei Augusto Drovetto Jr. - drovetto@gmail.com
20 * @license http://www.gnu.org/copyleft/gpl.html GPL
21 */
22class so_move_instances
23{
24        /**
25         * @var bool True se o usuário for administrador do expresso.
26         * @access private
27         */
28        private $isAdmin;
29
30        /**
31         * @var int ID do usuário logado no Expresso
32         * @access private
33         */
34        private $userID;
35
36        /**
37         * @var object Link para a ACL do Workflow.
38         * @access private
39         */
40        private $acl;
41
42        /**
43         * @var object Link para o Banco de Dados do Expresso.
44         * @access private
45         */
46        private $db;
47
48        /**
49         * Checa se o usuário possui direitos administrativos em um processo.
50         * @param int $processID O ID do processo que se quer checar se o usuário tem direito administrativo.
51         * @return bool True em caso de sucesso. Em caso de falha, a execução é abortada.
52         * @access private
53         */
54        private function _checkAccess($processID = null)
55        {
56                /* the user is an administrator */
57                if ($this->isAdmin)
58                        return true;
59
60                if (!is_null($processID))
61                {
62                        if ($this->acl->checkUserGroupAccessToResource('PRO', $this->userID, $processID))
63                                return true;
64                        else
65                                die(serialize("Você não tem permissão para executar este procedimento!"));
66                }
67                if ($this->acl->checkUserGroupAccessToType('PRO', $this->userID))
68                        return true;
69
70                die(serialize("Você não tem permissão para executar este procedimento!"));
71        }
72
73        /**
74         * Verifica se houve erro em alguma query do Banco de Dados.
75         * @param object $result O resultado de alguma query
76         * @return void
77         * @access private
78         */
79        private function _checkError($result)
80        {
81                if ($result === false)
82                        die(serialize("Ocorreu um erro ao se tentar executar a operação solicitada."));
83        }
84
85        /**
86         * Construtor da classe so_move_instances
87         * @return object
88         */
89        function so_move_instances()
90        {
91                $this->userID = $_SESSION['phpgw_info']['workflow']['account_id'];
92                $this->isAdmin = $_SESSION['phpgw_info']['workflow']['user_is_admin'];
93                $this->acl = &$GLOBALS['ajax']->acl;
94                $this->db = &$GLOBALS['workflow']['workflowObjects']->getDBGalaxia()->Link_ID;
95        }
96
97        /**
98         * Carrega a lista de processos que o usuário tem acesso.
99         * @return array Lista de processos.
100         * @access public
101         */
102        function loadProcesses()
103        {
104                $this->_checkAccess();
105
106                $where = array();
107                if (!$this->isAdmin)
108                {
109                        $processIDs = $this->acl->get_granted_processes($this->userID);
110                        if (count($processIDs) > 0)
111                                $where[] = 'wf_p_id IN (' . implode(',', $processIDs) . ')';
112                        else
113                                $where[] = 'wf_p_id IS NULL';
114                }
115                $processManager = new ProcessManager($this->db);
116
117                /* workaround to sort the result using two columns */
118                $items = $processManager->list_processes(0, -1, 'wf_name__ASC, wf_version ASC', '', implode(' AND ', $where));
119                $output = array();
120                foreach ($items['data'] as $item)
121                        $output[] = array(
122                                'wf_p_id' => $item['wf_p_id'],
123                                'wf_name' => $item['wf_name'],
124                                'wf_version' => $item['wf_version']);
125
126                return $output;
127        }
128
129        /**
130         * Carrega a lista de atividades de um processo (com exceção de atividades do tipo Standalone e View).
131         * @param int $processID O ID do processo do qual se quer a lista de atividades.
132         * @return array Lista de atividades de um processo.
133         * @access public
134         */
135        function loadProcessActivities($processID)
136        {
137                $this->_checkAccess($processID);
138
139                $activityManager = new ActivityManager($this->db);
140                $activities = $activityManager->list_activities($processID, 0, -1, 'wf_name__ASC', '', 'wf_type <> \'standalone\' AND wf_type <> \'view\'');
141                $output = array();
142                foreach ($activities['data'] as $activity)
143                        $output[] = array(
144                                'wf_activity_id' => $activity['wf_activity_id'],
145                                'wf_name' => $activity['wf_name'],
146                                'wf_type' => $activity['wf_type']);
147                return $output;
148        }
149
150        /**
151         * Faz um pré-relacionamento das atividades dos dois processos.
152         * @param array $fromActivities Lista de atividades do processo de origem.
153         * @param array $toActivities Lista de atividades do processo de destino.
154         * @param float $threshold Limiar que define a menor porcentagem de semelhança entre o nome de duas atividades para que estas sejam relacionadas.
155         * @return array Lista de atividades relacionadas.
156         * @access public
157         */
158        function matchActivities($fromActivities, $toActivities, $threshold)
159        {
160                $preOutput = array();
161                foreach ($fromActivities as $fromActivity)
162                {
163                        $fromActivityName = $fromActivity['wf_name'];
164                        $fromActivityID = $fromActivity['wf_activity_id'];
165                        foreach ($toActivities as $toActivity)
166                        {
167                                $toActivityName = $toActivity['wf_name'];
168                                $toActivityID = $toActivity['wf_activity_id'];
169                                $currentValue = isset($preOutput[$fromActivityID]) ? $preOutput[$fromActivityID]['value'] : 0;
170
171                                similar_text($fromActivityName, $toActivityName, $matchValue);
172                                if (($matchValue > $threshold) && ($matchValue > $currentValue))
173                                        $preOutput[$fromActivityID] = array(
174                                                'activityID' => $toActivityID,
175                                                'value' => $matchValue);
176                        }
177                }
178                $output = array();
179                foreach ($preOutput as $fromActivityID => $toActivityInfo)
180                        $output[] = array(
181                                'from' => $fromActivityID,
182                                'to' => $toActivityInfo['activityID']);
183
184                return $output;
185        }
186
187        /**
188         * Move as instâncias de um processo para outro.
189         * @param int $from O ID do processo de origem.
190         * @param int $to O ID do processo de destino.
191         * @param bool $active Indica se devem ser movidas as instâncias ativas.
192         * @param bool $completed Indica se devem ser movidas as instâncias finalizadas.
193         * @param array $activityMappings O relacionamento entre as atividades dos dois processos.
194         * @return bool TRUE em caso de sucesso e FALSE caso contrário.
195         * @access public
196         */
197        function moveInstances($from, $to, $activityMappings, $active, $completed)
198        {
199                $this->_checkAccess($from);
200                $this->_checkAccess($to);
201
202                if (($active || $completed) == false)
203                        return array('error' => 'Nenhuma instância foi movida. Selecione pelo menos uma das checkboxes do status das instâncias.');
204
205                $instanceStatus = array();
206                $instanceActivityStatus = array();
207                if ($active)
208                {
209                        $instanceStatus[] = "'active'";
210                        $instanceStatus[] = "'exception'";
211                        $instanceActivityStatus[] = "'running'";
212                }
213
214                if ($completed)
215                {
216                        $instanceStatus[] = "'completed'";
217                        $instanceStatus[] = "'aborted'";
218                        $instanceActivityStatus[] = "'completed'";
219
220                }
221
222                /* create an array for quick conversion between the old and the new activities ID */
223                $activitiesConvert = array();
224                foreach ($activityMappings as $toActivityID => $fromActivities)
225                        foreach ($fromActivities as $fromActivityID)
226                                $activitiesConvert[$fromActivityID] = $toActivityID;
227
228                $this->db->StartTrans();
229                $transactionResult = true;
230
231                /* update the instances table */
232                $resultSet = $this->db->query("SELECT wf_instance_id, wf_next_activity, wf_next_user FROM egw_wf_instances WHERE (wf_status IN (" . implode(', ', $instanceStatus) . ")) AND (wf_p_id = ?)", array($from));
233                $rows = $resultSet->GetArray(-1);
234                $instanceList = array();
235                if (is_array($rows))
236                {
237                        foreach ($rows as $row)
238                        {
239                                /* save the ID of the instances for future use */
240                                $instanceList[] = $row['wf_instance_id'];
241
242                                /* get the data and unserialize them */
243                                $oldInstance = array(
244                                        'wf_instance_id' => $row['wf_instance_id'],
245                                        'wf_next_activity' => unserialize(base64_decode($row['wf_next_activity'])),
246                                        'wf_next_user' => unserialize(base64_decode($row['wf_next_user'])));
247
248                                /* change the next activity */
249                                $newInstance['wf_next_activity'] = array();
250                                if (is_array($oldInstance['wf_next_activity']))
251                                {
252                                        foreach ($oldInstance['wf_next_activity'] as $k => $v)
253                                                $newInstance['wf_next_activity'][$activitiesConvert[$k]] = $activitiesConvert[$v];
254                                }
255
256                                /* change the next user */
257                                $newInstance['wf_next_user'] = array();
258                                if (is_array($oldInstance['wf_next_user']))
259                                {
260                                        foreach ($oldInstance['wf_next_user'] as $k => $v)
261                                                if ($k[0] == '*')
262                                                        $newInstance['wf_next_user']['*' . $activitiesConvert[substr($k, 1)]] = $v;
263                                                else
264                                                        $newInstance['wf_next_user'][$activitiesConvert[$k]] = $v;
265                                }
266
267                                /* serialize and encode the data */
268                                $newInstance['wf_next_activity'] = base64_encode(serialize($newInstance['wf_next_activity']));
269                                $newInstance['wf_next_user'] = base64_encode(serialize($newInstance['wf_next_user']));
270
271                                /* update the egw_wf_instances table */
272                                if (!$this->db->query("UPDATE egw_wf_instances SET wf_next_activity = ?, wf_next_user = ?, wf_p_id = ? WHERE (wf_instance_id = ?)", array($newInstance['wf_next_activity'], $newInstance['wf_next_user'], $to, $oldInstance['wf_instance_id'])))
273                                {
274                                        $this->db->FailTrans();
275                                        return array('error' => 'Erro atualizando a tabela de instâncias. Nenhuma modificação foi salva');
276                                }
277                        }
278                }
279                /* assure at least one element */
280                $instanceList[] = -1;
281
282                /* update the instance_activities table */
283                $instanceActivityList = array();
284                $resultSet = $this->db->query("SELECT wf_instance_id, wf_activity_id FROM egw_wf_instance_activities WHERE (wf_status IN (" . implode(', ', $instanceActivityStatus) . ")) AND (wf_activity_id IN (" . implode(', ', array_keys($activitiesConvert)) . "))");
285                $rows = $resultSet->GetArray(-1);
286                if (is_array($rows))
287                {
288                        foreach ($rows as $row)
289                        {
290                                /* save the instance ID and activity ID pair for future use */
291                                $instanceActivityList[] = array(
292                                        'iid' => $row['wf_instance_id'],
293                                        'aid' => $row['wf_activity_id']);
294
295                                /* update the activity ID */
296                                if (!$this->db->query("UPDATE egw_wf_instance_activities SET wf_activity_id = ? WHERE (wf_instance_id = ?) AND (wf_activity_id = ?)", array($activitiesConvert[$row['wf_activity_id']], $row['wf_instance_id'], $row['wf_activity_id'])))
297                                {
298                                        $this->db->FailTrans();
299                                        return array('error' => 'Erro atualizando a tabela que relaciona instâncias e atividades. Nenhuma modificação foi salva');
300                                }
301                        }
302                }
303                /* assure at least one element */
304                $instanceActivityList[] = array('iid' => -1, 'aid' => -1);
305
306                /* update the workitems of the modified instances */
307                $resultSet = $this->db->query("SELECT wf_item_id, wf_activity_id FROM egw_wf_workitems WHERE (wf_instance_id IN (" . implode(', ', $instanceList) . "))");
308                $rows = $resultSet->GetArray(-1);
309                if (is_array($rows))
310                {
311                        foreach ($rows as $row)
312                        {
313                                /* update the activity ID */
314                                if (!$this->db->query("UPDATE egw_wf_workitems SET wf_activity_id = ? WHERE (wf_item_id = ?)", array($activitiesConvert[$row['wf_activity_id']], $row['wf_item_id'])))
315                                {
316                                        $this->db->FailTrans();
317                                        return array('error' => 'Erro atualizando a tabela de workitems. Nenhuma modificação foi salva');
318                                }
319                        }
320                }
321
322                /* format the array elements for use in a SELECT SQL statement, e.g. [iid => 12, aid = 27] would produce (12, 27) */
323                $instanceActivityList = array_map(create_function('$e', 'return \'(\' . $e[\'iid\'] . \', \' . $e[\'aid\'] . \')\';'), $instanceActivityList);
324
325                /* update the interinstance relations of the modified rows of the instance_activities table */
326                $resultSet = $this->db->query("SELECT wf_parent_instance_id, wf_parent_activity_id FROM egw_wf_interinstance_relations WHERE ((wf_parent_instance_id, wf_parent_activity_id) IN (" . implode(', ', $instanceActivityList) . "))");
327                $rows = $resultSet->GetArray(-1);
328                if (is_array($rows))
329                {
330                        foreach ($rows as $row)
331                        {
332                                /* update the activity ID */
333                                if (!$this->db->query("UPDATE egw_wf_interinstance_relations SET wf_parent_activity_id = ? WHERE (wf_parent_instance_id = ?) AND (wf_parent_activity_id = ?)", array($activitiesConvert[$row['wf_parent_activity_id']], $row['wf_parent_instance_id'], $row['wf_parent_activity_id'])))
334                                {
335                                        $this->db->FailTrans();
336                                        return array('error' => 'Erro atualizando a tabela de relacionamento inter-instância. Nenhuma modificação foi salva');
337                                }
338                        }
339                }
340
341                /* in case of success, commit the modifications */
342                $this->db->CompleteTrans();
343                return true;
344        }
345}
346?>
Note: See TracBrowser for help on using the repository browser.