More work in progress on custom fields extension.
[timetracker.git] / plugins / CustomFields.class.php
1 <?php
2 // +----------------------------------------------------------------------+
3 // | Anuko Time Tracker
4 // +----------------------------------------------------------------------+
5 // | Copyright (c) Anuko International Ltd. (https://www.anuko.com)
6 // +----------------------------------------------------------------------+
7 // | LIBERAL FREEWARE LICENSE: This source code document may be used
8 // | by anyone for any purpose, and freely redistributed alone or in
9 // | combination with other software, provided that the license is obeyed.
10 // |
11 // | There are only two ways to violate the license:
12 // |
13 // | 1. To redistribute this code in source form, with the copyright
14 // |    notice or license removed or altered. (Distributing in compiled
15 // |    forms without embedded copyright notices is permitted).
16 // |
17 // | 2. To redistribute modified versions of this code in *any* form
18 // |    that bears insufficient indications that the modifications are
19 // |    not the work of the original author(s).
20 // |
21 // | This license applies to this document only, not any other software
22 // | that it may be combined with.
23 // |
24 // +----------------------------------------------------------------------+
25 // | Contributors:
26 // | https://www.anuko.com/time_tracker/credits.htm
27 // +----------------------------------------------------------------------+
28
29 class CustomFields {
30
31   // Definitions of custom field types.
32   const ENTITY_TIME = 1;    // Field is associated with time entries.
33   const ENTITY_USER = 2;    // Field is associated with users.
34   const ENTITY_PROJECT = 3; // Field is associated with projects.
35
36   const TYPE_TEXT = 1;     // A text field.
37   const TYPE_DROPDOWN = 2; // A dropdown field with pre-defined values.
38
39   var $fields = array();  // Array of custom fields for group.
40   var $options = array(); // Array of options for a dropdown custom field.
41
42   // Constructor.
43   function __construct() {
44     global $user;
45     $mdb2 = getConnection();
46
47     $group_id = $user->getGroup();
48     $org_id = $user->org_id;
49
50     // Get fields.
51     $sql = "select id, type, label, required from tt_custom_fields".
52       " where group_id = $group_id and org_id = $org_id and status = 1 and type > 0";
53     $res = $mdb2->query($sql);
54     if (!is_a($res, 'PEAR_Error')) {
55       while ($val = $res->fetchRow()) {
56         $this->fields[] = array('id'=>$val['id'],'type'=>$val['type'],'label'=>$val['label'],'required'=>$val['required'],'value'=>'');
57       }
58     }
59
60     // If we have a dropdown obtain options for it.
61     if ((count($this->fields) > 0) && ($this->fields[0]['type'] == CustomFields::TYPE_DROPDOWN)) {
62
63       $sql = "select id, value from tt_custom_field_options".
64         " where field_id = ".$this->fields[0]['id']." and group_id = $group_id and org_id = $org_id and status = 1 order by value";
65       $res = $mdb2->query($sql);
66       if (!is_a($res, 'PEAR_Error')) {
67         while ($val = $res->fetchRow()) {
68           $this->options[$val['id']] = $val['value'];
69         }
70       }
71     }
72   }
73
74   function insert($log_id, $field_id, $option_id, $value) {
75     global $user;
76     $mdb2 = getConnection();
77
78     $group_id = $user->getGroup();
79     $org_id = $user->org_id;
80
81     $sql = "insert into tt_custom_field_log (group_id, org_id, log_id, field_id, option_id, value)".
82       " values($group_id, $org_id, $log_id, $field_id, ".$mdb2->quote($option_id).", ".$mdb2->quote($value).")";
83     $affected = $mdb2->exec($sql);
84     return (!is_a($affected, 'PEAR_Error'));
85   }
86
87   function update($log_id, $field_id, $option_id, $value) {
88     if (!$field_id)
89       return true; // Nothing to update.
90
91     // Remove older custom field values, if any.
92     $res = $this->delete($log_id);
93     if (!$res)
94       return false;
95
96     if (!$value && !$option_id)
97       return true; // Do not insert NULL values.
98
99     return $this->insert($log_id, $field_id, $option_id, $value);
100   }
101
102   function delete($log_id) {
103     global $user;
104     $mdb2 = getConnection();
105
106     $group_id = $user->getGroup();
107     $org_id = $user->org_id;
108
109     $sql = "update tt_custom_field_log set status = null".
110       " where log_id = $log_id and group_id = $group_id and org_id = $org_id";
111     $affected = $mdb2->exec($sql);
112     return (!is_a($affected, 'PEAR_Error'));
113   }
114
115   function get($log_id) {
116     global $user;
117     $mdb2 = getConnection();
118
119     $group_id = $user->getGroup();
120     $org_id = $user->org_id;
121
122     $sql = "select id, field_id, option_id, value from tt_custom_field_log".
123       " where log_id = $log_id and group_id = $group_id and org_id = $org_id and status = 1";
124     $res = $mdb2->query($sql);
125     if (!is_a($res, 'PEAR_Error')) {
126       $fields = array();
127       while ($val = $res->fetchRow()) {
128         $fields[] = $val;
129       }
130       return $fields;
131     }
132     return false;
133   }
134
135   // insertOption adds a new option to a custom field.
136   static function insertOption($field_id, $option_name) {
137     global $user;
138     $mdb2 = getConnection();
139
140     $group_id = $user->getGroup();
141     $org_id = $user->org_id;
142
143     // Check if the option exists.
144     $id = 0;
145     $sql = "select id from tt_custom_field_options".
146       " where field_id = $field_id and group_id = $group_id and org_id = $org_id and value = ".$mdb2->quote($option_name);
147     $res = $mdb2->query($sql);
148     if (is_a($res, 'PEAR_Error'))
149       return false;
150     if ($val = $res->fetchRow()) $id = $val['id'];
151
152     // Insert option.
153     if (!$id) {
154       $sql = "insert into tt_custom_field_options (group_id, org_id, field_id, value)".
155         " values($group_id, $org_id, $field_id, ".$mdb2->quote($option_name).")";
156       $affected = $mdb2->exec($sql);
157       if (is_a($affected, 'PEAR_Error'))
158         return false;
159     }
160     return true;
161   }
162
163   // updateOption updates option name.
164   static function updateOption($id, $option_name) {
165     global $user;
166     $mdb2 = getConnection();
167
168     $group_id = $user->getGroup();
169     $org_id = $user->org_id;
170
171     $sql = "update tt_custom_field_options set value = ".$mdb2->quote($option_name).
172        " where id = $id and group_id = $group_id and org_id = $org_id";
173     $affected = $mdb2->exec($sql);
174     return (!is_a($affected, 'PEAR_Error'));
175   }
176
177   // delete Option deletes an option and all custom field log entries that used it.
178   static function deleteOption($id) {
179     global $user;
180     $mdb2 = getConnection();
181
182     $group_id = $user->getGroup();
183     $org_id = $user->org_id;
184
185     $field_id = CustomFields::getFieldIdForOption($id);
186     if (!$field_id) return false;
187
188     // Delete log entries with this option. TODO: why? Research impact.
189     $sql = "update tt_custom_field_log set status = null".
190       " where field_id = $field_id and group_id = $group_id and org_id = $org_id and value = ".$mdb2->quote($id);
191     $affected = $mdb2->exec($sql);
192     if (is_a($affected, 'PEAR_Error'))
193       return false;
194
195     // Delete the option.
196     $sql = "update tt_custom_field_options set status = null".
197       " where id = $id and group_id = $group_id and org_id = $org_id";
198     $affected = $mdb2->exec($sql);
199     return (!is_a($affected, 'PEAR_Error'));
200   }
201
202   // getOptions returns an array of options for a custom field.
203   static function getOptions($field_id) {
204     global $user;
205     $mdb2 = getConnection();
206
207     $group_id = $user->getGroup();
208     $org_id = $user->org_id;
209
210     // Get options.
211     $sql = "select id, value from tt_custom_field_options".
212       " where field_id = $field_id and group_id = $group_id and org_id = $org_id and status = 1 order by value";
213     $res = $mdb2->query($sql);
214     if (!is_a($res, 'PEAR_Error')) {
215       $options = array();
216       while ($val = $res->fetchRow()) {
217         $options[$val['id']] = $val['value'];
218       }
219       return $options;
220     }
221     return false;
222   }
223
224   // getOptionName returns an option name for a custom field.
225   static function getOptionName($id) {
226     global $user;
227     $mdb2 = getConnection();
228
229     $group_id = $user->getGroup();
230     $org_id = $user->org_id;
231
232     $sql = "select value from tt_custom_field_options".
233       " where id = $id and group_id = $group_id and org_id = $org_id and status = 1";
234     $res = $mdb2->query($sql);
235     if (!is_a($res, 'PEAR_Error')) {
236       $val = $res->fetchRow();
237       $name = $val['value'];
238       return $name;
239     }
240     return false;
241   }
242
243   // getFields returns an array of custom fields for group.
244   static function getFields() {
245     global $user;
246     $mdb2 = getConnection();
247
248     $group_id = $user->getGroup();
249     $org_id = $user->org_id;
250
251     $fields = array();
252     $sql = "select id, type, label from tt_custom_fields".
253       " where group_id = $group_id and org_id = $org_id and status = 1 and type > 0";
254     $res = $mdb2->query($sql);
255     if (!is_a($res, 'PEAR_Error')) {
256       while ($val = $res->fetchRow()) {
257         $fields[] = array('id'=>$val['id'],'type'=>$val['type'],'label'=>$val['label']);
258       }
259       return $fields;
260     }
261     return false;
262   }
263
264   // getField returns a custom field.
265   static function getField($id) {
266     global $user;
267     $mdb2 = getConnection();
268
269     $group_id = $user->getGroup();
270     $org_id = $user->org_id;
271
272     $sql = "select label, type, required from tt_custom_fields".
273       " where id = $id and group_id = $group_id and org_id = $org_id";
274     $res = $mdb2->query($sql);
275     if (!is_a($res, 'PEAR_Error')) {
276       $val = $res->fetchRow();
277       if (!$val)
278         return false;
279       return $val;
280     }
281     return false;
282   }
283
284   // getFieldIdForOption returns field id from an associated option id.
285   static function getFieldIdForOption($option_id) {
286     global $user;
287     $mdb2 = getConnection();
288
289     $group_id = $user->getGroup();
290     $org_id = $user->org_id;
291
292     $sql = "select field_id from tt_custom_field_options".
293       " where id = $option_id and group_id = $group_id and org_id = $org_id";
294     $res = $mdb2->query($sql);
295     if (!is_a($res, 'PEAR_Error')) {
296       $val = $res->fetchRow();
297       $field_id = $val['field_id'];
298       return $field_id;
299     }
300     return false;
301   }
302
303   // The insertField inserts a custom field for group.
304   static function insertField($field_name, $entity_type, $field_type, $required) {
305     global $user;
306     $mdb2 = getConnection();
307
308     $group_id = $user->getGroup();
309     $org_id = $user->org_id;
310
311     $sql = "insert into tt_custom_fields (group_id, org_id, type, label, required, status)".
312       " values($group_id, $org_id, $field_type, ".$mdb2->quote($field_name).", $required, 1)";
313     $affected = $mdb2->exec($sql);
314     return (!is_a($affected, 'PEAR_Error'));
315   }
316
317   // The updateField updates custom field for group.
318   static function updateField($id, $name, $type, $required) {
319     global $user;
320     $mdb2 = getConnection();
321
322     $group_id = $user->getGroup();
323     $org_id = $user->org_id;
324
325     $sql = "update tt_custom_fields set label = ".$mdb2->quote($name).", type = $type, required = $required".
326       " where id = $id and group_id = $group_id and org_id = $org_id";
327     $affected = $mdb2->exec($sql);
328     return (!is_a($affected, 'PEAR_Error'));
329   }
330
331   // The deleteField deletes a custom field, its options and log entries for group.
332   static function deleteField($field_id) {
333     global $user;
334     $mdb2 = getConnection();
335
336     $group_id = $user->getGroup();
337     $org_id = $user->org_id;
338
339     // Mark log entries as deleted. TODO: why are we doing this? Research impact.
340     $sql = "update tt_custom_field_log set status = null".
341       " where field_id = $field_id and group_id = $group_id and org_id = $org_id";
342     $affected = $mdb2->exec($sql);
343     if (is_a($affected, 'PEAR_Error'))
344       return false;
345
346     // Mark field options as deleted.
347     $sql = "update tt_custom_field_options set status = null".
348       " where field_id = $field_id and group_id = $group_id and org_id = $org_id";
349     $affected = $mdb2->exec($sql);
350     if (is_a($affected, 'PEAR_Error'))
351       return false;
352
353     // Mark custom field as deleted.
354     $sql = "update tt_custom_fields set status = null".
355       " where id = $field_id and group_id = $group_id and org_id = $org_id";
356     $affected = $mdb2->exec($sql);
357     return (!is_a($affected, 'PEAR_Error'));
358   }
359 }