1<?php
2/* Copyright (c) 1998-2009 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4define('UDF_TYPE_TEXT', 1);
5define('UDF_TYPE_SELECT', 2);
6define('UDF_TYPE_WYSIWYG', 3);
7define('UDF_NO_VALUES', 1);
8define('UDF_DUPLICATE_VALUES', 2);
9
10
11/**
12* Additional user data fields definition
13*
14* @author Stefan Meyer <meyer@leifos.com>
15*
16* @version $Id$
17* @ingroup ServicesUser
18*/
19class ilUserDefinedFields
20{
21    public $db = null;
22    public $definitions = array();
23
24    private $field_visible_registration = 0;
25
26    /**
27     * Constructor is private -> use getInstance
28     * These definition are used e.g in User XML import.
29     * To avoid instances of this class for every user object during import,
30     * it caches this object in a singleton.
31     *
32     */
33    private function __construct()
34    {
35        global $DIC;
36
37        $ilDB = $DIC['ilDB'];
38
39        $this->db = &$ilDB;
40
41        $this->__read();
42    }
43
44    /**
45     * Get instance
46     * @return ilUserDefinedFields
47     */
48    public static function _getInstance()
49    {
50        static $udf = null;
51
52        if (!is_object($udf)) {
53            return $udf = new ilUserDefinedFields();
54        }
55        return $udf;
56    }
57
58    public function fetchFieldIdFromImportId($a_import_id)
59    {
60        global $DIC;
61
62        $ilSetting = $DIC['ilSetting'];
63
64        if (!strlen($a_import_id)) {
65            return 0;
66        }
67        $parts = explode('_', $a_import_id);
68
69        if ($parts[0] != 'il') {
70            return 0;
71        }
72        if ($parts[1] != $ilSetting->get('inst_id', 0)) {
73            return 0;
74        }
75        if ($parts[2] != 'udf') {
76            return 0;
77        }
78        if ($parts[3]) {
79            // Check if field exists
80            if (is_array($this->definitions["$parts[3]"])) {
81                return $parts[3];
82            }
83        }
84        return 0;
85    }
86    public function fetchFieldIdFromName($a_name)
87    {
88        foreach ($this->definitions as $definition) {
89            if ($definition['field_name'] == $a_name) {
90                return $definition['field_id'];
91            }
92        }
93        return 0;
94    }
95
96    /**
97     * @return array
98     */
99    public function getDefinitions()
100    {
101        return $this->definitions ? $this->definitions : array();
102    }
103
104    public function getDefinition($a_id)
105    {
106        return is_array($this->definitions[$a_id]) ? $this->definitions[$a_id] : array();
107    }
108
109    public function getVisibleDefinitions()
110    {
111        foreach ($this->definitions as $id => $definition) {
112            if ($definition['visible']) {
113                $visible_definition[$id] = $definition;
114            }
115        }
116        return $visible_definition ? $visible_definition : array();
117    }
118
119    public function getLocalUserAdministrationDefinitions()
120    {
121        foreach ($this->definitions as $id => $definition) {
122            if ($definition['visib_lua']) {
123                $visible_definition[$id] = $definition;
124            }
125        }
126        return $visible_definition ? $visible_definition : array();
127    }
128
129    public function getChangeableLocalUserAdministrationDefinitions()
130    {
131        foreach ($this->definitions as $id => $definition) {
132            if ($definition['changeable_lua']) {
133                $visible_definition[$id] = $definition;
134            }
135        }
136        return $visible_definition ? $visible_definition : array();
137    }
138
139    public function getRegistrationDefinitions()
140    {
141        foreach ($this->definitions as $id => $definition) {
142            if ($definition['visib_reg']) {
143                $visible_definition[$id] = $definition;
144            }
145        }
146        return $visible_definition ? $visible_definition : array();
147    }
148
149    public function getSearchableDefinitions()
150    {
151        foreach ($this->definitions as $id => $definition) {
152            if ($definition['searchable']) {
153                $searchable_definition[$id] = $definition;
154            }
155        }
156        return $searchable_definition ? $searchable_definition : array();
157    }
158
159    public function getRequiredDefinitions()
160    {
161        foreach ($this->definitions as $id => $definition) {
162            if ($definition['required']) {
163                $required_definition[$id] = $definition;
164            }
165        }
166        return $required_definition ? $required_definition : array();
167    }
168
169    /**
170     * get
171     *
172     * @access public
173     * @param
174     *
175     */
176    public function getCourseExportableFields()
177    {
178        foreach ($this->definitions as $id => $definition) {
179            if ($definition['course_export']) {
180                $cexp_definition[$id] = $definition;
181            }
182        }
183        return $cexp_definition ? $cexp_definition : array();
184    }
185
186    /**
187     * get fields visible in groups
188     *
189     * @access public
190     * @param
191     *
192     */
193    public function getGroupExportableFields()
194    {
195        foreach ($this->definitions as $id => $definition) {
196            if ($definition['group_export']) {
197                $cexp_definition[$id] = $definition;
198            }
199        }
200        return $cexp_definition ? $cexp_definition : array();
201    }
202
203    /**
204     * Get exportable field
205     * @param int $a_obj_id
206     * @return
207     */
208    public function getExportableFields($a_obj_id)
209    {
210        if (ilObject::_lookupType($a_obj_id) == 'crs') {
211            return $this->getCourseExportableFields();
212        }
213        if (ilObject::_lookupType($a_obj_id) == 'grp') {
214            return $this->getGroupExportableFields();
215        }
216        return array();
217    }
218
219
220    public function setFieldName($a_name)
221    {
222        $this->field_name = $a_name;
223    }
224    public function getFieldName()
225    {
226        return $this->field_name;
227    }
228    public function setFieldType($a_type)
229    {
230        $this->field_type = $a_type;
231    }
232
233    public function isPluginType()
234    {
235        if (!$this->field_type) {
236            return false;
237        }
238        switch ($this->field_type) {
239            case UDF_TYPE_TEXT:
240            case UDF_TYPE_SELECT:
241            case UDF_TYPE_WYSIWYG:
242                return false;
243
244            default:
245                return true;
246        }
247    }
248
249    public function getFieldType()
250    {
251        return $this->field_type;
252    }
253    public function setFieldValues($a_values)
254    {
255        $this->field_values = array();
256        foreach ($a_values as $value) {
257            if (strlen($value)) {
258                $this->field_values[] = $value;
259            }
260        }
261    }
262    public function getFieldValues()
263    {
264        return $this->field_values ? $this->field_values : array();
265    }
266
267    public function enableVisible($a_visible)
268    {
269        $this->field_visible = $a_visible;
270    }
271    public function enabledVisible()
272    {
273        return $this->field_visible;
274    }
275    public function enableVisibleLocalUserAdministration($a_visible)
276    {
277        $this->field_visib_lua = $a_visible;
278    }
279    public function enabledVisibleLocalUserAdministration()
280    {
281        return $this->field_visib_lua;
282    }
283    public function enableChangeable($a_changeable)
284    {
285        $this->field_changeable = $a_changeable;
286    }
287    public function enabledChangeable()
288    {
289        return $this->field_changeable;
290    }
291    public function enableChangeableLocalUserAdministration($a_changeable)
292    {
293        $this->field_changeable_lua = $a_changeable;
294    }
295    public function enabledChangeableLocalUserAdministration()
296    {
297        return $this->field_changeable_lua;
298    }
299    public function enableRequired($a_required)
300    {
301        $this->field_required = $a_required;
302    }
303    public function enabledRequired()
304    {
305        return $this->field_required;
306    }
307    public function enableSearchable($a_searchable)
308    {
309        $this->field_searchable = $a_searchable;
310    }
311    public function enabledSearchable()
312    {
313        return $this->field_searchable;
314    }
315    public function enableExport($a_export)
316    {
317        $this->field_export = $a_export;
318    }
319    public function enabledExport()
320    {
321        return $this->field_export;
322    }
323    public function enableCourseExport($a_course_export)
324    {
325        $this->field_course_export = $a_course_export;
326    }
327    public function enabledCourseExport()
328    {
329        return $this->field_course_export;
330    }
331    public function enableGroupExport($a_group_export)
332    {
333        $this->field_group_export = $a_group_export;
334    }
335    public function enabledGroupExport()
336    {
337        return $this->field_group_export;
338    }
339
340    public function enableCertificate($a_c)
341    {
342        $this->field_certificate = $a_c;
343    }
344    public function enabledCertificate()
345    {
346        return $this->field_certificate;
347    }
348
349    public function enableVisibleRegistration($a_visible_registration)
350    {
351        $this->field_visible_registration = $a_visible_registration;
352    }
353    public function enabledVisibleRegistration()
354    {
355        return $this->field_visible_registration;
356    }
357
358    /**
359     * @param mixed[] $a_values
360     * @param bool $a_with
361     * @return array
362     */
363    public function fieldValuesToSelectArray($a_values, $a_with_selection_info = true)
364    {
365        global $DIC;
366
367        $lng = $DIC->language();
368        $values = [];
369        if ($a_with_selection_info) {
370            $values[''] = $lng->txt('please_select');
371        }
372        foreach ($a_values as $value) {
373            $values[$value] = $value;
374        }
375        if (count($values) > (int) $a_with_selection_info) {
376            return $values;
377        }
378        return [];
379    }
380
381    public function validateValues()
382    {
383        $number = 0;
384        $unique = array();
385        foreach ($this->getFieldValues() as $value) {
386            if (!strlen($value)) {
387                continue;
388            }
389            $number++;
390            $unique[$value] = $value;
391        }
392
393        if (!count($unique)) {
394            return UDF_NO_VALUES;
395        }
396        if ($number != count($unique)) {
397            return UDF_DUPLICATE_VALUES;
398        }
399        return 0;
400    }
401
402    public function nameExists($a_field_name)
403    {
404        global $DIC;
405
406        $ilDB = $DIC['ilDB'];
407
408        $query = "SELECT * FROM udf_definition " .
409            "WHERE field_name = " . $this->db->quote($a_field_name, 'text') . " ";
410        $res = $ilDB->query($query);
411
412        return (bool) $res->numRows();
413    }
414
415    public function add()
416    {
417        global $DIC;
418
419        $ilDB = $DIC['ilDB'];
420
421        // Add definition entry
422        $next_id = $ilDB->nextId('udf_definition');
423
424        $values = array(
425            'field_id' => array('integer',$next_id),
426            'field_name' => array('text',$this->getFieldName()),
427            'field_type' => array('integer', (int) $this->getFieldType()),
428            'field_values' => array('clob',serialize($this->getFieldValues())),
429            'visible' => array('integer', (int) $this->enabledVisible()),
430            'changeable' => array('integer', (int) $this->enabledChangeable()),
431            'required' => array('integer', (int) $this->enabledRequired()),
432            'searchable' => array('integer', (int) $this->enabledSearchable()),
433            'export' => array('integer', (int) $this->enabledExport()),
434            'course_export' => array('integer', (int) $this->enabledCourseExport()),
435            'registration_visible' => array('integer', (int) $this->enabledVisibleRegistration()),
436            'visible_lua' => array('integer', (int) $this->enabledVisibleLocalUserAdministration()),
437            'changeable_lua' => array('integer', (int) $this->enabledChangeableLocalUserAdministration()),
438            'group_export' => array('integer', (int) $this->enabledGroupExport()),
439            'certificate' => array('integer', (int) $this->enabledCertificate()),
440        );
441
442        $ilDB->insert('udf_definition', $values);
443
444        // add table field in usr_defined_data
445        $field_id = $next_id;
446
447
448        $this->__read();
449
450        return $field_id;
451    }
452    public function delete($a_id)
453    {
454        global $DIC;
455
456        $ilDB = $DIC['ilDB'];
457
458        // Delete definitions
459        $query = "DELETE FROM udf_definition " .
460            "WHERE field_id = " . $this->db->quote($a_id, 'integer') . " ";
461        $res = $ilDB->manipulate($query);
462
463        // Delete usr_data entries
464        //		$ilDB->dropTableColumn('udf_data','f_'.$a_id);
465        include_once("./Services/User/classes/class.ilUserDefinedData.php");
466        ilUserDefinedData::deleteEntriesOfField($a_id);
467
468        $this->__read();
469
470        return true;
471    }
472
473    public function update($a_id)
474    {
475        global $DIC;
476
477        $ilDB = $DIC['ilDB'];
478
479        $values = array(
480            'field_name' => array('text',$this->getFieldName()),
481            'field_type' => array('integer', (int) $this->getFieldType()),
482            'field_values' => array('clob',serialize($this->getFieldValues())),
483            'visible' => array('integer', (int) $this->enabledVisible()),
484            'changeable' => array('integer', (int) $this->enabledChangeable()),
485            'required' => array('integer', (int) $this->enabledRequired()),
486            'searchable' => array('integer', (int) $this->enabledSearchable()),
487            'export' => array('integer', (int) $this->enabledExport()),
488            'course_export' => array('integer', (int) $this->enabledCourseExport()),
489            'registration_visible' => array('integer', (int) $this->enabledVisibleRegistration()),
490            'visible_lua' => array('integer', (int) $this->enabledVisibleLocalUserAdministration()),
491            'changeable_lua' => array('integer', (int) $this->enabledChangeableLocalUserAdministration()),
492            'group_export' => array('integer', (int) $this->enabledGroupExport()),
493            'certificate' => array('integer', (int) $this->enabledCertificate())
494        );
495        $ilDB->update('udf_definition', $values, array('field_id' => array('integer',$a_id)));
496        $this->__read();
497
498        return true;
499    }
500
501
502
503    // Private
504    public function __read()
505    {
506        global $DIC;
507
508        $ilSetting = $DIC['ilSetting'];
509
510        $query = "SELECT * FROM udf_definition ";
511        $res = $this->db->query($query);
512
513        $this->definitions = array();
514        while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
515            $this->definitions[$row->field_id]['field_id'] = $row->field_id;
516            $this->definitions[$row->field_id]['field_name'] = $row->field_name;
517            $this->definitions[$row->field_id]['field_type'] = $row->field_type;
518            $this->definitions[$row->field_id]['il_id'] = 'il_' . $ilSetting->get('inst_id', 0) . '_udf_' . $row->field_id;
519
520            // #16953
521            $tmp = $sort = array();
522            $is_numeric = true;
523            foreach ((array) unserialize($row->field_values) as $item) {
524                if (!is_numeric($item)) {
525                    $is_numeric = false;
526                }
527                $sort[] = array("value" => $item);
528            }
529            foreach (ilUtil::sortArray($sort, "value", "asc", $is_numeric) as $item) {
530                $tmp[] = $item["value"];
531            }
532
533            $this->definitions[$row->field_id]['field_values'] = $tmp;
534            $this->definitions[$row->field_id]['visible'] = $row->visible;
535            $this->definitions[$row->field_id]['changeable'] = $row->changeable;
536            $this->definitions[$row->field_id]['required'] = $row->required;
537            $this->definitions[$row->field_id]['searchable'] = $row->searchable;
538            $this->definitions[$row->field_id]['export'] = $row->export;
539            $this->definitions[$row->field_id]['course_export'] = $row->course_export;
540            $this->definitions[$row->field_id]['visib_reg'] = $row->registration_visible;
541            $this->definitions[$row->field_id]['visib_lua'] = $row->visible_lua;
542            $this->definitions[$row->field_id]['changeable_lua'] = $row->changeable_lua;
543            $this->definitions[$row->field_id]['group_export'] = $row->group_export;
544            // fraunhpatch start
545            $this->definitions[$row->field_id]['certificate'] = $row->certificate;
546            // fraunhpatch end
547        }
548
549        return true;
550    }
551
552
553    public function deleteValue($a_field_id, $a_value_id)
554    {
555        global $DIC;
556
557        $ilDB = $DIC['ilDB'];
558
559        $definition = $this->getDefinition($a_field_id);
560
561        $counter = 0;
562        $new_values = array();
563        foreach ($definition['field_values'] as $value) {
564            if ($counter++ != $a_value_id) {
565                $new_values[] = $value;
566            } else {
567                $old_value = $value;
568            }
569        }
570
571        $values = array(
572            'field_values' => array('clob',serialize($new_values)));
573        $ilDB->update('udf_definition', $values, array('field_id' => array('integer',$a_field_id)));
574
575
576        // sets value to '' where old value is $old_value
577        include_once("./Services/User/classes/class.ilUserDefinedData.php");
578        ilUserDefinedData::deleteFieldValue($a_field_id, $old_value);
579
580        // fianally read data
581        $this->__read();
582
583        return true;
584    }
585
586    public function toXML()
587    {
588        include_once './Services/Xml/classes/class.ilXmlWriter.php';
589        $xml_writer = new ilXmlWriter();
590
591        $this->addToXML($xml_writer);
592
593        return $xml_writer->xmlDumpMem(false);
594    }
595
596    /**
597    *	add user defined field data to xml (using usr dtd)
598    *	@param*XmlWriter $xml_writer
599    */
600    public function addToXML($xml_writer)
601    {
602        $xml_writer->xmlStartTag("UDFDefinitions");
603        foreach ($this->getDefinitions() as $definition) {
604            $attributes = array(
605                "Id" => $definition ["il_id"],
606                "Type" => $definition["field_type"] == UDF_TYPE_SELECT? "SELECT" : "TEXT",
607                "Visible" => $definition["visible"]? "TRUE" : "FALSE",
608                "Changeable" => $definition["changeable"]? "TRUE" : "FALSE",
609                "Required" => $definition["required"]? "TRUE" : "FALSE",
610                "Searchable" => $definition["searchable"]? "TRUE" : "FALSE",
611                "CourseExport" => $definition["course_export"]? "TRUE" : "FALSE",
612                "GroupExport" => $definition["group_export"]? "TRUE" : "FALSE",
613                "Certificate" => $definition["certificate"]? "TRUE" : "FALSE",
614                "Export" => $definition["export"]? "TRUE" : "FALSE",
615                "RegistrationVisible" => $definition["visib_reg"]? "TRUE" : "FALSE",
616                "LocalUserAdministrationVisible" => $definition["visib_lua"]? "TRUE" : "FALSE",
617                "LocalUserAdministrationChangeable" => $definition["changeable_lua"]? "TRUE" : "FALSE",
618
619            );
620            $xml_writer->xmlStartTag("UDFDefinition", $attributes);
621            $xml_writer->xmlElement('UDFName', null, $definition['field_name']);
622            if ($definition["field_type"] == UDF_TYPE_SELECT) {
623                $field_values = $definition["field_values"];
624                foreach ($field_values as $field_value) {
625                    $xml_writer->xmlElement('UDFValue', null, $field_value);
626                }
627            }
628            $xml_writer->xmlEndTag("UDFDefinition");
629        }
630        $xml_writer->xmlEndTag("UDFDefinitions");
631    }
632
633
634    public static function _newInstance()
635    {
636        static $udf = null;
637
638        return $udf = new ilUserDefinedFields();
639    }
640}
641