source: contrib/ProjectManager/inc/class.soprojectmanager.inc.php @ 3594

Revision 3594, 13.0 KB checked in by afernandes, 13 years ago (diff)

Ticket #1416 - Disponibilizado o módulo ProjectManager? para a comunidade

  • Property svn:executable set to *
Line 
1<?php
2/**
3 * ProjectManager - General (projects) storage object
4 *
5 * @link http://www.egroupware.org
6 * @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
7 * @package projectmanager
8 * @copyright (c) 2005 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
9 * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
10 * @version $Id: class.soprojectmanager.inc.php 25098 2008-03-17 08:49:22Z ralfbecker $
11 */
12
13include_once(PHPGW_INCLUDE_ROOT.'/etemplate/inc/class.so_sql.inc.php');
14
15/**
16 * General storage object of the projectmanager: access the main project data
17 *
18 * Tables: phpgw_pm_projects, phpgw_pm_extra, phpgw_pm_roles, phpgw_pm_members
19 *
20 * A project P is the parent of an other project C, if link_id1=P.pm_id and link_id2=C.pm_id !
21 */
22class soprojectmanager extends so_sql
23{
24        /**
25         * Table name 'phpgw_links'
26         *
27         * @var string
28         */
29        var $links_table = 'phpgw_links';
30        /**
31         * Configuration data
32         *
33         * @var array
34         */
35        var $config = array(
36                'customfields' => array(),
37        );
38        /**
39         * Custom fields
40         *
41         * @var array
42         */
43        var $customfields;
44        /**
45         * Name of customefields table
46         *
47         * @var string
48         */
49        var $extra_table = 'phpgw_pm_extra';
50        /**
51         * Name of project-members table
52         *
53         * @var string
54         */
55        var $members_table = 'phpgw_pm_members';
56        /**
57         * Name of roles table
58         *
59         * @var string
60         */
61        var $roles_table = 'phpgw_pm_roles';
62        /**
63         * Join with the members and the roles table to get the role-ACL of the current user
64         *
65         * @var string
66         */
67        var $acl_join;
68        /**
69         * Extracolumns from the members table
70         *
71         * @var array/string
72         */
73        var $acl_extracols='role_acl';
74        /**
75         * ACL grants from other users
76         *
77         * @var array
78         */
79        var $grants;
80        var $read_grants,$private_grants;
81
82        /**
83         * Constructor, calls the constructor of the extended class
84         *
85         * @param int $pm_id id of the project to load, default null
86         * @return soprojectmanger
87         */
88        function soprojectmanager($pm_id=null)
89        {
90                $this->so_sql('projectmanager','phpgw_pm_projects');
91               
92                $config =& CreateObject('phpgwapi.config','projectmanager');
93                $config->read_repository();
94                $this->config =& $config->config_data;
95                unset($config);
96                $this->customfields =& $this->config['customfields'];
97                $this->config['duration_format'] = str_replace(',','',$this->config['duration_units']).','.$this->config['hours_per_workday'];
98
99                $this->grants = $GLOBALS['phpgw']->acl->get_grants('projectmanager');
100                $this->user = (int) $GLOBALS['phpgw_info']['user']['account_id'];
101
102                $this->read_grants = $this->private_grants = array();
103                foreach($this->grants as $owner => $rights)
104                {
105                        if ($rights) $this->read_grants[] = $owner;             // ANY ACL implies READ!
106                       
107                        if ($rights & PHPGW_ACL_PRIVATE) $this->private_grants[] = $owner;
108                }
109                $this->acl_join = "LEFT JOIN $this->members_table ON ($this->table_name.pm_id=$this->members_table.pm_id AND member_uid=$this->user) ".
110                        " LEFT JOIN $this->roles_table ON $this->members_table.role_id=$this->roles_table.role_id";
111
112                if ($pm_id) $this->read($pm_id);
113        }
114       
115        /**
116         * reads a project
117         *
118         * reimplemented to handle custom fields
119         */
120        function read($keys)
121        {
122                //echo "<p>soprojectmanager::read(".print_r($keys,true).")</p>\n";
123
124                if ($keys && is_numeric($keys) && $this->data['pm_id'] == $keys ||
125                        $keys['pm_id'] &&  $this->data['pm_id'] == $keys['pm_id'])
126                {
127                        return $this->data;
128                }
129                if (!parent::read($keys))
130                {
131                        return false;
132                }
133                if ($this->customfields)
134                {
135                        $this->db->select($this->extra_table,'*',array('pm_id' => $this->data['pm_id']),__LINE__,__FILE__);
136
137                        while (($row = $this->db->row(true)))
138                        {
139                                $this->data['#'.$row['pm_extra_name']] = $row['pm_extra_value'];
140                        }
141                }
142                // query project_members and their roles
143/*
144                $this->db->select($this->members_table,'*',$this->members_table.'.pm_id='.(int)$this->data['pm_id'],__LINE__,__FILE__,
145                        False,'',False,0,"LEFT JOIN $this->roles_table ON $this->members_table.role_id=$this->roles_table.role_id");
146       
147                while (($row = $this->db->row(true)))
148                {
149                        $this->data['pm_members'][$row['member_uid']] = $row;
150                }
151*/
152                $this->data['pm_members'] = $this->read_members($this->data['pm_id']);
153                $this->data['role_acl'] = $this->data['pm_members'][$this->user]['role_acl'];
154               
155                return $this->data;
156        }
157       
158        /**
159         * Read the projectmembers of one or more projects
160         *
161         * @param int/array $pm_id
162         * @return array with projectmembers
163         */
164        function read_members($pm_id)
165        {
166                $this->db->select($this->members_table,'*,'.$this->members_table.'.pm_id AS pm_id',
167                        $this->db->expression($this->members_table,$this->members_table.'.',array('pm_id'=>$pm_id)),__LINE__,__FILE__,
168                        False,'',False,0,"LEFT JOIN $this->roles_table ON $this->members_table.role_id=$this->roles_table.role_id");
169               
170                while(($row = $this->db->row(true)))
171                {
172                        $members[$row['pm_id']][$row['member_uid']] = $row;
173                }
174                return is_array($pm_id) ? $members : $members[$pm_id];
175        }
176       
177        /**
178         * saves a project
179         *
180         * reimplemented to handle custom fields and set modification and creation data
181         *
182         * @param array $keys if given $keys are copied to data before saveing => allows a save as
183         * @return int 0 on success and errno != 0 else
184         */
185        function save($keys=null)
186        {
187                //echo "soprojectmanager::save(".print_r($keys,true).") this->data="; _debug_array($this->data);
188               
189                if (is_array($keys) && count($keys))
190                {
191                        $this->data_merge($keys);
192                        $keys = null;
193                }
194                if (parent::save($keys) == 0 && $this->data['pm_id'])
195                {
196                        if ($this->customfields)
197                        {
198                                // custome fields: first delete all, then save the ones with non-empty content
199                                $this->db->delete($this->extra_table,array('pm_id' => $this->data['pm_id']),__LINE__,__FILE__);
200                                foreach($this->customfields as $name => $data)
201                                {
202                                        if ($name && isset($this->data['#'.$name]) && !empty($this->data['#'.$name]))
203                                        {
204                                                $this->db->insert($this->extra_table,array(
205                                                        'pm_id'          => $this->data['pm_id'],
206                                                        'pm_extra_name'  => $name,
207                                                        'pm_extra_value' => $this->data['#'.$name],
208                                                ),false,__LINE__,__FILE__);
209                                        }
210                                }
211                        }
212                        // project-members: first delete all, then save the (still) assigned ones
213                        $this->db->delete($this->members_table,array('pm_id' => $this->data['pm_id']),__LINE__,__FILE__);
214                        foreach((array)$this->data['pm_members'] as $uid => $data)
215                        {
216                                $this->db->insert($this->members_table,array(
217                                        'pm_id'      => $this->data['pm_id'],
218                                        'member_uid' => $uid,
219                                        'role_id'    => $data['role_id'],
220                                        'member_availibility' => $data['member_availibility'],
221                                ),false,__LINE__,__FILE__);
222                        }
223                }
224                return $this->db->Errno;
225        }
226       
227        /**
228         * merges in new values from the given new data-array
229         *
230         * reimplemented to also merge the customfields
231         *
232         * @param $new array in form col => new_value with values to set
233         */
234        function data_merge($new)
235        {
236                parent::data_merge($new);
237               
238                if (is_array($this->customfields))
239                {
240                        foreach($this->customfields as $name => $data)
241                        {
242                                if (isset($new['#'.$name]))
243                                {
244                                        $this->data['#'.$name] = $new['#'.$name];
245                                }
246                        }
247                }
248        }
249
250        /**
251         * search projects, re-implemented to include sub-cats and allow to filter for subs and mains
252         *
253         * @param array/string $criteria array of key and data cols, OR a SQL query (content for WHERE), fully quoted (!)
254         * @param boolean $only_keys True returns only keys, False returns all cols
255         * @param string $order_by fieldnames + {ASC|DESC} separated by colons ','
256         * @param string/array $extra_cols string or array of strings to be added to the SELECT, eg. "count(*) as num"
257         * @param string $wildcard appended befor and after each criteria
258         * @param boolean $empty False=empty criteria are ignored in query, True=empty have to be empty in row
259         * @param string $op defaults to 'AND', can be set to 'OR' too, then criteria's are OR'ed together
260         * @param int/boolean $start if != false, return only maxmatch rows begining with start
261         * @param array $filter if set (!=null) col-data pairs, to be and-ed (!) into the query without wildcards
262         * @param string/boolean $join=true sql to do a join, added as is after the table-name, default true=add join for acl
263         * @return array of matching rows (the row is an array of the cols) or False
264         */
265        function search($criteria,$only_keys=True,$order_by='',$extra_cols='',$wildcard='',$empty=False,$op='AND',$start=false,$filter=null,$join=true,$need_full_no_count=false)
266        {
267                // include sub-categories in the search
268                if ($filter['cat_id'])
269                {
270                        if (!is_object($GLOBALS['phpgw']->categories))
271                        {
272                                $GLOBALS['phpgw']->categories =& CreateObject('phpgwapi.categories');
273                        }
274                        $filter['cat_id'] = $GLOBALS['phpgw']->categories->return_all_children($filter['cat_id']);
275                }
276                if ($join === true)     // add acl-join, to get role_acl of current user
277                {
278                        $join = $this->acl_join;
279                       
280                        if (!is_array($extra_cols)) $extra_cols = $extra_cols ? explode(',',$extra_cols) : array();
281                        $extra_cols = array_merge($extra_cols,array(
282                                $this->acl_extracols,
283                                $this->table_name.'.pm_id AS pm_id',
284                        ));
285                        if ($only_keys === true) $only_keys=''; // otherwise we use ambigues pm_id
286       
287                        if (isset($criteria['pm_id']))
288                        {
289                                $criteria[$this->table_name.'.pm_id'] = $criteria['pm_id'];
290                                unset($criteria['pm_id']);
291                        }
292                        if (isset($filter['pm_id']) && $filter['pm_id'])
293                        {
294                                $filter[$this->table_name.'.pm_id'] = $filter['pm_id'];
295                                unset($filter['pm_id']);
296                        }
297                        // include an ACL filter for read-access
298                        $filter[] = "(pm_access='anonym' OR pm_access='public' AND pm_creator IN (".implode(',',$this->read_grants).
299                                ") OR pm_access='private' AND pm_creator IN (".implode(',',$this->private_grants).')'.
300                                ($join == $this->acl_join ? ' OR '.$this->roles_table.'.role_acl!=0' : '').')';
301                }
302                if ($filter['subs_or_mains'])
303                {
304/* old code using a sub-query
305                        $ids = "SELECT link_id2 FROM $this->links_table WHERE link_app2='projectmanager' AND link_app1='projectmanager'";
306                       
307                        if (is_array($filter['subs_or_mains']))         // sub-projects of given parent-projects
308                        {
309                                $ids .= ' AND '.$this->db->expression($this->links_table,array('link_id1' => $filter['subs_or_mains']));
310                                $filter['subs_or_mains'] = 'subs';
311                        }
312                        if (!$this->db->capabilities['sub_queries'])
313                        {
314                                $this->db->query($ids,__LINE__,__FILE__);
315                                $ids = array();
316                                while($this->db->next_record())
317                                {
318                                        $ids[] = $this->db->f(0);
319                                }
320                                $ids = count($ids) ? implode(',',$ids) : 0;
321                        }
322                        $filter[] = $this->table_name.'.pm_id '.($filter['subs_or_mains'] == 'mains' ? 'NOT ' : '').'IN ('.$ids.')';
323*/
324                        // new code using a JOIN
325                        if ($filter['subs_or_mains'] == 'mains')
326                        {
327                                $filter[] = 'link_id2 IS NULL';
328                                $join .= ' LEFT';
329                        }
330                        // postgres 8.3 requires cast as link_idx is varchar and pm_id an integer, the cast should be no problem for other DB's
331                        $join .= " JOIN $this->links_table ON link_app2='projectmanager' AND link_app1='projectmanager' AND link_id2=CAST($this->table_name.pm_id AS CHAR)";
332
333                        if (is_array($filter['subs_or_mains'])) // sub-projects of given parent-projects
334                        {
335                                $join .= ' AND '.$this->db->expression($this->links_table,array('link_id1' => $filter['subs_or_mains']));
336                        }
337                }
338                unset($filter['subs_or_mains']);
339               
340                return parent::search($criteria,$only_keys,$order_by,$extra_cols,$wildcard,$empty,$op,$start,$filter,$join,$need_full_no_count);
341        }
342       
343        /**
344         * reimplemented to set some defaults and cope with ambigues pm_id column
345         *
346         * @param string $value_col='pm_title' column-name for the values of the array, can also be an expression aliased with AS
347         * @param string $key_col='pm_id' column-name for the keys, default '' = same as $value_col: returns a distinct list
348         * @param array $filter=array() to filter the entries
349         * @return array with key_col => value_col pairs, ordered by value_col
350         */
351        function query_list($value_col='pm_title',$key_col='pm_id',$filter=array('pm_status'=>'active'))
352        {
353                if ($key_col == 'pm_id') $key_col = $this->table_name.'.pm_id AS pm_id';
354               
355                return parent::query_list($value_col,$key_col,$filter);
356        }
357       
358        /**
359         * read the general availebility of one or all users
360         *
361         * A not set availibility is by default 100%
362         *
363         * @param int $uid user-id or 0 to read all
364         * @return array uid => availibility
365         */
366        function get_availibility($uid=0)
367        {
368                $where = array('pm_id' => 0);
369               
370                if ($uid) $where['member_uid'] = $uid;
371               
372                $this->db->select($this->members_table,'member_uid,member_availibility',$where,__LINE__,__FILE__);
373                $avails = array();
374                while (($row = $this->db->row(true)))
375                {
376                        $avails[$row['member_uid']] = empty($row['member_availibility']) ? 100.0 : $row['member_availibility'];
377                }
378                return $avails;
379        }
380       
381        /**
382         * set or delete the general availibility of a user
383         *
384         * A not set availibility is by default 100%
385         *
386         * @param int $uid user-id
387         * @param float $availiblity=null percentage to set or nothing to delete the avail. for the user
388         */
389        function set_availibility($uid,$availibility=null)
390        {
391                if (!is_numeric($uid)) return;
392
393                if (!is_null($availibility) && !empty($availibility) && $availibility != 100.0)
394                {
395                        $this->db->insert($this->members_table,array(
396                                'member_availibility' => $availibility
397                        ),array(
398                                'member_uid' => $uid,
399                                'pm_id'      => 0,
400                        ),__LINE__,__FILE__);
401                }
402                else
403                {
404                        $this->db->delete($this->members_table,array(
405                                'pm_id' => 0,
406                                'member_uid' => $uid,
407                        ),__LINE__,__FILE__);
408                }
409        }
410}
Note: See TracBrowser for help on using the repository browser.