1<?php
2/* Copyright (c) 1998-2010 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4include_once("./Services/Tracking/classes/class.ilLPTableBaseGUI.php");
5
6/**
7 * Learning progress table: One object, rows: users, columns: properties
8 * Example: A course, rows: members, columns: name, status, mark, ...
9 *
10 * PD, Personal Learning Progress -> UserObjectsProps
11 * PD, Learning Progress of Users -> UserAggObjectsProps
12 * Crs, Learnign Progress of Participants -> ObjectUsersProps
13 * Details -> UserObjectsProps
14 *
15 * More:
16 * PropUsersObjects (Grading Overview in Course)
17 * @author Alex Killing <alex.killing@gmx.de>
18 * @version $Id$
19 *
20 * @ilCtrl_Calls ilTrObjectUsersPropsTableGUI: ilFormPropertyDispatchGUI
21 * @ingroup ServicesTracking
22 */
23class ilTrObjectUsersPropsTableGUI extends ilLPTableBaseGUI
24{
25    protected $user_fields; // array
26    protected $filter; // array
27    protected $in_course; // int
28    protected $in_group; // int
29    protected $has_edit; // bool
30    protected $has_collection; // bool
31    protected $has_multi; // bool
32
33    /**
34    * Constructor
35    */
36    public function __construct($a_parent_obj, $a_parent_cmd, $a_obj_id, $a_ref_id, $a_print_view = false)
37    {
38        global $DIC;
39
40        $ilCtrl = $DIC['ilCtrl'];
41        $ilUser = $DIC['ilUser'];
42        $tree = $DIC['tree'];
43        $rbacsystem = $DIC['rbacsystem'];
44
45        $this->setId("troup");
46        $this->obj_id = $a_obj_id;
47        $this->ref_id = $a_ref_id;
48        $this->type = ilObject::_lookupType($a_obj_id);
49
50        $this->in_group = $tree->checkForParentType($this->ref_id, "grp");
51        if ($this->in_group) {
52            $this->in_group = ilObject::_lookupObjId($this->in_group);
53        } else {
54            $this->in_course = $tree->checkForParentType($this->ref_id, "crs");
55            if ($this->in_course) {
56                $this->in_course = ilObject::_lookupObjId($this->in_course);
57            }
58        }
59
60        parent::__construct($a_parent_obj, $a_parent_cmd);
61
62        $this->parseTitle($a_obj_id, "trac_participants");
63
64        if ($a_print_view) {
65            $this->setPrintMode(true);
66        }
67
68        if (!$this->getPrintMode()) {
69            // see ilObjCourseGUI::addMailToMemberButton()
70            include_once "Services/Mail/classes/class.ilMail.php";
71            $mail = new ilMail($ilUser->getId());
72            if ($rbacsystem->checkAccess("internal_mail", $mail->getMailObjectReferenceId())) {
73                $this->addMultiCommand("mailselectedusers", $this->lng->txt("send_mail"));
74            }
75            $this->lng->loadLanguageModule('user');
76            $this->addMultiCommand(
77                'addToClipboard',
78                $this->lng->txt('clipboard_add_btn')
79            );
80            $this->addColumn("", "", 1);
81            $this->has_multi = true;
82        }
83
84        $labels = $this->getSelectableColumns();
85        foreach ($this->getSelectedColumns() as $c) {
86            $first = $c;
87
88            // list cannot be sorted by udf fields (separate query)
89            // because of pagination only core fields can be sorted
90            $sort_id = (substr($c, 0, 4) == "udf_") ? "" : $c;
91
92            $this->addColumn($labels[$c]["txt"], $sort_id);
93        }
94
95        if (!$this->getPrintMode()) {
96            $this->addColumn($this->lng->txt("actions"), "");
97        }
98        $this->setSelectAllCheckbox('uid');
99        $this->setExternalSorting(true);
100        $this->setExternalSegmentation(true);
101        $this->setEnableHeader(true);
102        $this->setFormAction($ilCtrl->getFormActionByClass(get_class($this)));
103        $this->setRowTemplate("tpl.object_users_props_row.html", "Services/Tracking");
104        $this->setEnableTitle(true);
105        $this->setShowTemplates(true);
106        $this->setExportFormats(array(self::EXPORT_CSV, self::EXPORT_EXCEL));
107
108        if ($first) {
109            $this->setDefaultOrderField($first);
110            $this->setDefaultOrderDirection("asc");
111        }
112
113        $this->initFilter();
114
115        $this->getItems();
116
117        // #13807
118        include_once './Services/Tracking/classes/class.ilLearningProgressAccess.php';
119        $this->has_edit = ilLearningProgressAccess::checkPermission('edit_learning_progress', $this->ref_id);
120
121        /* currently not active, needs to be revised
122        include_once "Services/Object/classes/class.ilObjectLP.php";
123        include_once "Services/Tracking/classes/collection/class.ilLPCollection.php";
124        $objlp = ilObjectLP::getInstance($this->obj_id);
125        $this->has_collection = in_array($objlp->getCurrentMode(), ilLPCollection::getCollectionModes());
126        */
127    }
128
129    /**
130     * Get selectable columns
131     *
132     * @param
133     * @return
134     */
135    public function getSelectableColumns()
136    {
137        if ($this->selectable_columns) {
138            return $this->selectable_columns;
139        }
140
141        $cols = $this->getSelectableUserColumns($this->in_course, $this->in_group);
142        $this->user_fields = $cols[1];
143        $this->selectable_columns = $cols[0];
144
145        return $this->selectable_columns;
146    }
147
148    /**
149    * Get user items
150    */
151    public function getItems()
152    {
153        global $DIC;
154
155        $lng = $DIC['lng'];
156
157        $this->determineOffsetAndOrder();
158
159        include_once("./Services/Tracking/classes/class.ilTrQuery.php");
160
161        $additional_fields = $this->getSelectedColumns();
162
163        // only if object is [part of] course/group
164        $check_agreement = false;
165        if ($this->in_course) {
166            // privacy (if course agreement is activated)
167            include_once "Services/PrivacySecurity/classes/class.ilPrivacySettings.php";
168            $privacy = ilPrivacySettings::_getInstance();
169            if ($privacy->courseConfirmationRequired()) {
170                $check_agreement = $this->in_course;
171            }
172        } elseif ($this->in_group) {
173            // privacy (if group agreement is activated)
174            include_once "Services/PrivacySecurity/classes/class.ilPrivacySettings.php";
175            $privacy = ilPrivacySettings::_getInstance();
176            if ($privacy->groupConfirmationRequired()) {
177                $check_agreement = $this->in_group;
178            }
179        }
180
181        $tr_data = ilTrQuery::getUserDataForObject(
182            $this->ref_id,
183            ilUtil::stripSlashes($this->getOrderField()),
184            ilUtil::stripSlashes($this->getOrderDirection()),
185            ilUtil::stripSlashes($this->getOffset()),
186            ilUtil::stripSlashes($this->getLimit()),
187            $this->getCurrentFilter(),
188            $additional_fields,
189            $check_agreement,
190            $this->user_fields
191        );
192
193        if (count($tr_data["set"]) == 0 && $this->getOffset() > 0) {
194            $this->resetOffset();
195            $tr_data = ilTrQuery::getUserDataForObject(
196                $this->ref_id,
197                ilUtil::stripSlashes($this->getOrderField()),
198                ilUtil::stripSlashes($this->getOrderDirection()),
199                ilUtil::stripSlashes($this->getOffset()),
200                ilUtil::stripSlashes($this->getLimit()),
201                $this->getCurrentFilter(),
202                $additional_fields,
203                $check_agreement,
204                $this->user_fields
205            );
206        }
207
208        $this->setMaxCount($tr_data["cnt"]);
209        $this->setData($tr_data["set"]);
210    }
211
212
213    /**
214    * Init filter
215    */
216    public function initFilter()
217    {
218        global $DIC;
219
220        $lng = $DIC['lng'];
221
222        foreach ($this->getSelectableColumns() as $column => $meta) {
223            // no udf!
224            switch ($column) {
225                case "firstname":
226                case "lastname":
227                case "mark":
228                case "u_comment":
229                case "institution":
230                case "department":
231                case "title":
232                case "street":
233                case "zipcode":
234                case "city":
235                case "country":
236                case "email":
237                case "matriculation":
238                case "login":
239                    if ($column != "mark" ||
240                        ilObjectLP::supportsMark($this->type)) {
241                        $item = $this->addFilterItemByMetaType($column, ilTable2GUI::FILTER_TEXT, true, $meta["txt"]);
242                        $this->filter[$column] = $item->getValue();
243                    }
244                    break;
245
246                case "first_access":
247                case "last_access":
248                case "create_date":
249                case 'status_changed':
250                    $item = $this->addFilterItemByMetaType($column, ilTable2GUI::FILTER_DATETIME_RANGE, true, $meta["txt"]);
251                    $this->filter[$column] = $item->getDate();
252                    break;
253
254                case "birthday":
255                    $item = $this->addFilterItemByMetaType($column, ilTable2GUI::FILTER_DATE_RANGE, true, $meta["txt"]);
256                    $this->filter[$column] = $item->getDate();
257                    break;
258
259                case "read_count":
260                case "percentage":
261                    $item = $this->addFilterItemByMetaType($column, ilTable2GUI::FILTER_NUMBER_RANGE, true, $meta["txt"]);
262                    $this->filter[$column] = $item->getValue();
263                    break;
264
265                case "gender":
266                    $item = $this->addFilterItemByMetaType("gender", ilTable2GUI::FILTER_SELECT, true, $meta["txt"]);
267                    $item->setOptions(array(
268                        "" => $lng->txt("trac_all"),
269                        "n" => $lng->txt("gender_n"),
270                        "m" => $lng->txt("gender_m"),
271                        "f" => $lng->txt("gender_f"),
272                    ));
273                    $this->filter["gender"] = $item->getValue();
274                    break;
275
276                case "sel_country":
277                    $item = $this->addFilterItemByMetaType("sel_country", ilTable2GUI::FILTER_SELECT, true, $meta["txt"]);
278
279                    $options = array();
280                    include_once("./Services/Utilities/classes/class.ilCountry.php");
281                    foreach (ilCountry::getCountryCodes() as $c) {
282                        $options[$c] = $lng->txt("meta_c_" . $c);
283                    }
284                    asort($options);
285                    $item->setOptions(array("" => $lng->txt("trac_all")) + $options);
286
287                    $this->filter["sel_country"] = $item->getValue();
288                    break;
289
290                case "status":
291                    include_once "Services/Tracking/classes/class.ilLPStatus.php";
292                    $item = $this->addFilterItemByMetaType("status", ilTable2GUI::FILTER_SELECT, true, $meta["txt"]);
293                    $item->setOptions(array("" => $lng->txt("trac_all"),
294                        ilLPStatus::LP_STATUS_NOT_ATTEMPTED_NUM + 1 => $lng->txt(ilLPStatus::LP_STATUS_NOT_ATTEMPTED),
295                        ilLPStatus::LP_STATUS_IN_PROGRESS_NUM + 1 => $lng->txt(ilLPStatus::LP_STATUS_IN_PROGRESS),
296                        ilLPStatus::LP_STATUS_COMPLETED_NUM + 1 => $lng->txt(ilLPStatus::LP_STATUS_COMPLETED),
297                        ilLPStatus::LP_STATUS_FAILED_NUM + 1 => $lng->txt(ilLPStatus::LP_STATUS_FAILED)));
298                    $this->filter["status"] = $item->getValue();
299                    if (is_numeric($this->filter["status"])) {
300                        $this->filter["status"]--;
301                    }
302                    break;
303
304                case "language":
305                    $item = $this->addFilterItemByMetaType("language", ilTable2GUI::FILTER_LANGUAGE, true);
306                    $this->filter["language"] = $item->getValue();
307                    break;
308
309                case "spent_seconds":
310                    if (ilObjectLP::supportsSpentSeconds($this->type)) {
311                        $item = $this->addFilterItemByMetaType("spent_seconds", ilTable2GUI::FILTER_DURATION_RANGE, true, $meta["txt"]);
312                        $this->filter["spent_seconds"]["from"] = $item->getCombinationItem("from")->getValueInSeconds();
313                        $this->filter["spent_seconds"]["to"] = $item->getCombinationItem("to")->getValueInSeconds();
314                    }
315                    break;
316            }
317        }
318    }
319
320    /**
321    * Fill table row
322    */
323    protected function fillRow($data)
324    {
325        global $DIC;
326
327        $ilCtrl = $DIC['ilCtrl'];
328        $lng = $DIC['lng'];
329        $objDefinition = $DIC['objDefinition'];
330
331        if ($this->has_multi) {
332            $this->tpl->setVariable("USER_ID", $data["usr_id"]);
333        }
334
335        foreach ($this->getSelectedColumns() as $c) {
336            if (!(bool) $data["privacy_conflict"]) {
337                if ($c == 'status' && $data[$c] != ilLPStatus::LP_STATUS_COMPLETED_NUM) {
338                    $timing = $this->showTimingsWarning($this->ref_id, $data["usr_id"]);
339                    if ($timing) {
340                        if ($timing !== true) {
341                            $timing = ": " . ilDatePresentation::formatDate(new ilDate($timing, IL_CAL_UNIX));
342                        } else {
343                            $timing = "";
344                        }
345                        $this->tpl->setCurrentBlock('warning_img');
346                        $this->tpl->setVariable('WARNING_IMG', ilUtil::getImagePath('time_warn.svg'));
347                        $this->tpl->setVariable('WARNING_ALT', $this->lng->txt('trac_time_passed') . $timing);
348                        $this->tpl->parseCurrentBlock();
349                    }
350                }
351
352                // #7694
353                if ($c == 'login' && !$data["active"]) {
354                    $this->tpl->setCurrentBlock('inactive_bl');
355                    $this->tpl->setVariable('TXT_INACTIVE', $lng->txt("inactive"));
356                    $this->tpl->parseCurrentBlock();
357                }
358
359                $val = $this->parseValue($c, $data[$c], $this->type);
360            } else {
361                if ($c == 'login') {
362                    $this->tpl->setCurrentBlock('inactive_bl');
363                    $this->tpl->setVariable('TXT_INACTIVE', $lng->txt("status_no_permission"));
364                    $this->tpl->parseCurrentBlock();
365                }
366
367                $val = "&nbsp;";
368            }
369
370            $this->tpl->setCurrentBlock("user_field");
371            $this->tpl->setVariable("VAL_UF", $val);
372            $this->tpl->parseCurrentBlock();
373        }
374
375        $ilCtrl->setParameterByClass("illplistofobjectsgui", "user_id", $data["usr_id"]);
376
377        if (!$this->getPrintMode() && !(bool) $data["privacy_conflict"]) {
378            // details for containers and collections
379            if ($this->has_collection ||
380                $objDefinition->isContainer($this->type)) {
381                $this->tpl->setCurrentBlock("item_command");
382                $this->tpl->setVariable("HREF_COMMAND", $ilCtrl->getLinkTargetByClass("illplistofobjectsgui", "userdetails"));
383                $this->tpl->setVariable("TXT_COMMAND", $lng->txt('details'));
384                $this->tpl->parseCurrentBlock();
385            }
386
387            if ($this->has_edit) {
388                $this->tpl->setCurrentBlock("item_command");
389                $this->tpl->setVariable("HREF_COMMAND", $ilCtrl->getLinkTargetByClass("illplistofobjectsgui", "edituser"));
390                $this->tpl->setVariable("TXT_COMMAND", $lng->txt('edit'));
391                $this->tpl->parseCurrentBlock();
392            }
393        }
394
395        $ilCtrl->setParameterByClass("illplistofobjectsgui", 'user_id', '');
396    }
397
398    protected function fillHeaderExcel(ilExcel $a_excel, &$a_row)
399    {
400        $labels = $this->getSelectableColumns();
401        $cnt = 0;
402        foreach ($this->getSelectedColumns() as $c) {
403            $a_excel->setCell($a_row, $cnt++, $labels[$c]["txt"]);
404        }
405
406        $a_excel->setBold("A" . $a_row . ":" . $a_excel->getColumnCoord($cnt - 1) . $a_row);
407    }
408
409    protected function fillRowExcel(ilExcel $a_excel, &$a_row, $a_set)
410    {
411        $cnt = 0;
412        foreach ($this->getSelectedColumns() as $c) {
413            if ($c != 'status') {
414                $val = $this->parseValue($c, $a_set[$c], $this->type);
415            } else {
416                $val = ilLearningProgressBaseGUI::_getStatusText((int) $a_set[$c]);
417            }
418            $a_excel->setCell($a_row, $cnt++, $val);
419        }
420    }
421
422    protected function fillHeaderCSV($a_csv)
423    {
424        $labels = $this->getSelectableColumns();
425        foreach ($this->getSelectedColumns() as $c) {
426            $a_csv->addColumn($labels[$c]["txt"]);
427        }
428
429        $a_csv->addRow();
430    }
431
432    protected function fillRowCSV($a_csv, $a_set)
433    {
434        foreach ($this->getSelectedColumns() as $c) {
435            if ($c != 'status') {
436                $val = $this->parseValue($c, $a_set[$c], $this->type);
437            } else {
438                $val = ilLearningProgressBaseGUI::_getStatusText((int) $a_set[$c]);
439            }
440            $a_csv->addColumn($val);
441        }
442
443        $a_csv->addRow();
444    }
445}
446