1<?php
2/* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4require_once './Modules/Test/classes/inc.AssessmentConstants.php';
5require_once 'Modules/TestQuestionPool/classes/class.assQuestion.php';
6/**
7 * Export class for tests
8 *
9 * @author Helmut Schottmüller <helmut.schottmueller@mac.com>
10 * @author Maximilian Becker <mbecker@databay.de>
11 * @author Björn Heyser <bheyser@databay.de>
12 *
13 * @version $Id$
14 *
15 * @ingroup ModulesTest
16 */
17abstract class ilTestExport
18{
19    /** @var  ilErrorHandling $err */
20    public $err;			// error object
21
22    /** @var  ilDBInterface $db */
23    public $db;			// database object
24
25    /** @var  ILIAS $ilias */
26    public $ilias;			// ilias object
27
28    /** @var  ilObjTest $test_obj */
29    public $test_obj;		// test object
30
31    public $inst_id;		// installation id
32    public $mode;
33
34    /** @var ilLanguage $lng */
35    private $lng;
36
37    private $resultsfile;
38
39    protected $resultExportingEnabledForTestExport = false;
40
41    /**
42     * @var ilTestParticipantList
43     */
44    protected $forcedAccessFilteredParticipantList = null;
45
46    /**
47     * Constructor
48     */
49    public function __construct(&$a_test_obj, $a_mode = "xml")
50    {
51        global $DIC;
52        $ilErr = $DIC['ilErr'];
53        $ilDB = $DIC['ilDB'];
54        $ilias = $DIC['ilias'];
55        $lng = $DIC['lng'];
56
57        $this->test_obj = &$a_test_obj;
58
59        $this->err = &$ilErr;
60        $this->ilias = &$ilias;
61        $this->db = &$ilDB;
62        $this->mode = $a_mode;
63        $this->lng = &$lng;
64
65        $this->inst_id = IL_INST_ID;
66
67        $date = time();
68        $this->export_dir = $this->test_obj->getExportDirectory();
69        switch ($this->mode) {
70            case "results":
71                $this->subdir = $date . "__" . $this->inst_id . "__" .
72                    "tst__results_" . $this->test_obj->getId();
73                break;
74            case "aggregated":
75                $this->subdir = $date . "__" . $this->inst_id . "__" .
76                    "test__aggregated__results_" . $this->test_obj->getId();
77                break;
78            default:
79                $this->subdir = $date . "__" . $this->inst_id . "__" .
80                    "tst" . "_" . $this->test_obj->getId();
81                $this->filename = $this->subdir . ".xml";
82                $this->resultsfile = $date . "__" . $this->inst_id . "__" .
83                    "results" . "_" . $this->test_obj->getId() . ".xml";
84                $this->qti_filename = $date . "__" . $this->inst_id . "__" .
85                    "qti" . "_" . $this->test_obj->getId() . ".xml";
86                break;
87        }
88        $this->filename = $this->subdir . "." . $this->getExtension();
89    }
90
91    /**
92     * @return boolean
93     */
94    public function isResultExportingEnabledForTestExport()
95    {
96        return $this->resultExportingEnabledForTestExport;
97    }
98
99    /**
100     * @param boolean $resultExprtingEnabledForTestExport
101     */
102    public function setResultExportingEnabledForTestExport($resultExprtingEnabledForTestExport)
103    {
104        $this->resultExportingEnabledForTestExport = $resultExprtingEnabledForTestExport;
105    }
106
107    /**
108     * @return ilTestParticipantList
109     */
110    public function getForcedAccessFilteredParticipantList()
111    {
112        return $this->forcedAccessFilteredParticipantList;
113    }
114
115    /**
116     * @param ilTestParticipantList $forcedAccessFilteredParticipantList
117     */
118    public function setForcedAccessFilteredParticipantList(ilTestParticipantList $forcedAccessFilteredParticipantList)
119    {
120        $this->forcedAccessFilteredParticipantList = $forcedAccessFilteredParticipantList;
121    }
122
123    /**
124     * @return ilTestParticipantList
125     */
126    public function getAccessFilteredParticipantList()
127    {
128        if ($this->getForcedAccessFilteredParticipantList() instanceof ilTestParticipantList) {
129            return $this->getForcedAccessFilteredParticipantList();
130        }
131
132        return $this->test_obj->buildStatisticsAccessFilteredParticipantList();
133    }
134
135    public function getExtension()
136    {
137        switch ($this->mode) {
138            case "results":
139                return "csv"; break;
140            default:
141                return "xml"; break;
142        }
143    }
144
145    public function getInstId()
146    {
147        return $this->inst_id;
148    }
149
150
151    /**
152    *   build export file (complete zip file)
153    *
154    *   @access public
155    *   @return
156    */
157    public function buildExportFile()
158    {
159        switch ($this->mode) {
160            case "results":
161                return $this->buildExportResultFile();
162                break;
163            default:
164                return $this->buildExportFileXML();
165                break;
166        }
167    }
168
169    /**
170    * build xml export file
171    */
172    public function buildExportResultFile()
173    {
174        global $DIC;
175        $ilBench = $DIC['ilBench'];
176        $log = $DIC['log'];
177
178        //get Log File
179        $expDir = $this->test_obj->getExportDirectory();
180
181        // make_directories
182        $this->test_obj->createExportDirectory();
183        include_once "./Services/Utilities/classes/class.ilUtil.php";
184        ilUtil::makeDir($this->export_dir);
185
186        include_once './Services/Logging/classes/class.ilLog.php';
187        $expLog = new ilLog($expDir, "export.log");
188        $expLog->delete();
189        $expLog->setLogFormat("");
190        $expLog->write(date("[y-m-d H:i:s] ") . "Start Export Of Results");
191
192        $data = $this->exportToCSV($deliver = false);
193        $file = fopen($this->export_dir . "/" . $this->filename, "w");
194        fwrite($file, $data);
195        fclose($file);
196
197        $excelfile = $this->exportToExcel($deliver = false);
198        @copy($excelfile, $this->export_dir . "/" . str_replace($this->getExtension(), "xlsx", $this->filename));
199        @unlink($excelfile);
200        // end
201        $expLog->write(date("[y-m-d H:i:s] ") . "Finished Export of Results");
202
203        return $this->export_dir . "/" . $this->filename;
204    }
205
206    /**
207     * Exports the aggregated results to the Microsoft Excel file format
208     * @param boolean $deliver TRUE to directly deliver the file, FALSE to return the binary data
209     * @return string
210     */
211    protected function aggregatedResultsToExcel($deliver = true)
212    {
213        $data = $this->test_obj->getAggregatedResultsData();
214
215        require_once 'Modules/TestQuestionPool/classes/class.ilAssExcelFormatHelper.php';
216        $worksheet = new ilAssExcelFormatHelper();
217        $worksheet->addSheet($this->lng->txt('tst_results_aggregated'));
218
219        $row = 1;
220        $col = 0;
221        $worksheet->setCell($row, $col++, $this->lng->txt('result'));
222        $worksheet->setCell($row, $col++, $this->lng->txt('value'));
223
224        $worksheet->setBold('A' . $row . ':' . $worksheet->getColumnCoord($col - 1) . $row);
225
226        $row++;
227        foreach ($data['overview'] as $key => $value) {
228            $col = 0;
229            $worksheet->setCell($row, $col++, $key);
230            $worksheet->setCell($row, $col++, $value);
231            $row++;
232        }
233
234        $row++;
235        $col = 0;
236
237        $worksheet->setCell($row, $col++, $this->lng->txt('question_id'));
238        $worksheet->setCell($row, $col++, $this->lng->txt('question_title'));
239        $worksheet->setCell($row, $col++, $this->lng->txt('average_reached_points'));
240        $worksheet->setCell($row, $col++, $this->lng->txt('points'));
241        $worksheet->setCell($row, $col++, $this->lng->txt('percentage'));
242        $worksheet->setCell($row, $col++, $this->lng->txt('number_of_answers'));
243
244        $worksheet->setBold('A' . $row . ':' . $worksheet->getColumnCoord($col - 1) . $row);
245
246        $row++;
247        foreach ($data['questions'] as $key => $value) {
248            $col = 0;
249            $worksheet->setCell($row, $col++, $key);
250            $worksheet->setCell($row, $col++, $value[0]);
251            $worksheet->setCell($row, $col++, $value[4]);
252            $worksheet->setCell($row, $col++, $value[5]);
253            $worksheet->setCell($row, $col++, $value[6]);
254            $worksheet->setCell($row, $col++, $value[3]);
255            $row++;
256        }
257
258        if ($deliver) {
259            $worksheet->sendToClient(
260                ilUtil::getASCIIFilename(preg_replace("/\s/", '_', $this->test_obj->getTitle() . '_aggregated')) . '.xlsx'
261            );
262        } else {
263            $excelfile = ilUtil::ilTempnam();
264            $worksheet->writeToFile($excelfile);
265            return $excelfile . '.xlsx';
266        }
267    }
268
269    /**
270    * Exports the aggregated results to CSV
271    *
272    * @param boolean $deliver TRUE to directly deliver the file, FALSE to return the data
273    */
274    protected function aggregatedResultsToCSV($deliver = true)
275    {
276        $data = $this->test_obj->getAggregatedResultsData();
277        $rows = array();
278        array_push($rows, array(
279            $this->lng->txt("result"),
280            $this->lng->txt("value")
281        ));
282        foreach ($data["overview"] as $key => $value) {
283            array_push($rows, array(
284                $key,
285                $value
286            ));
287        }
288        array_push($rows, array(
289            $this->lng->txt("question_id"),
290            $this->lng->txt("question_title"),
291            $this->lng->txt("average_reached_points"),
292            $this->lng->txt("points"),
293            $this->lng->txt("percentage"),
294            $this->lng->txt("number_of_answers")
295        ));
296        foreach ($data["questions"] as $key => $value) {
297            array_push($rows, array(
298                $key,
299                $value[0],
300                $value[4],
301                $value[5],
302                $value[6],
303                $value[3]
304            ));
305        }
306        $csv = "";
307        $separator = ";";
308        foreach ($rows as $evalrow) {
309            $csvrow = &$this->test_obj->processCSVRow($evalrow, true, $separator);
310            $csv .= join($separator, $csvrow) . "\n";
311        }
312        if ($deliver) {
313            ilUtil::deliverData($csv, ilUtil::getASCIIFilename($this->test_obj->getTitle() . "_aggregated.csv"));
314            exit;
315        } else {
316            return $csv;
317        }
318    }
319
320    /**
321     * Exports the evaluation data to the Microsoft Excel file format
322     *
323     * @param bool    $deliver
324     * @param string  $filterby
325     * @param string  $filtertext Filter text for the user data
326     * @param boolean $passedonly TRUE if only passed user datasets should be exported, FALSE otherwise
327     *
328     * @return string
329     */
330    public function exportToExcel($deliver = true, $filterby = "", $filtertext = "", $passedonly = false)
331    {
332        $this->test_obj->setAccessFilteredParticipantList($this->getAccessFilteredParticipantList());
333
334        if (strcmp($this->mode, "aggregated") == 0) {
335            return $this->aggregatedResultsToExcel($deliver);
336        }
337
338        require_once 'Modules/TestQuestionPool/classes/class.ilAssExcelFormatHelper.php';
339
340        $worksheet = new ilAssExcelFormatHelper();
341        $worksheet->addSheet($this->lng->txt('tst_results'));
342
343        $additionalFields = $this->test_obj->getEvaluationAdditionalFields();
344
345        $row = 1;
346        $col = 0;
347
348        if ($this->test_obj->getAnonymity()) {
349            $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('counter'));
350        } else {
351            $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('name'));
352            $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('login'));
353        }
354
355        if (count($additionalFields)) {
356            foreach ($additionalFields as $fieldname) {
357                if (strcmp($fieldname, "exam_id") == 0) {
358                    $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('exam_id_label'));
359                    continue;
360                }
361                $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt($fieldname));
362            }
363        }
364
365        $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('tst_stat_result_resultspoints'));
366        $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('maximum_points'));
367        $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('tst_stat_result_resultsmarks'));
368
369        if ($this->test_obj->getECTSOutput()) {
370            $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('ects_grade'));
371        }
372
373        $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('tst_stat_result_qworkedthrough'));
374        $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('tst_stat_result_qmax'));
375        $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('tst_stat_result_pworkedthrough'));
376        $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('tst_stat_result_timeofwork'));
377        $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('tst_stat_result_atimeofwork'));
378        $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('tst_stat_result_firstvisit'));
379        $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('tst_stat_result_lastvisit'));
380        $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('tst_stat_result_mark_median'));
381        $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('tst_stat_result_rank_participant'));
382        $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('tst_stat_result_rank_median'));
383        $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('tst_stat_result_total_participants'));
384        $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('tst_stat_result_median'));
385        $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('scored_pass'));
386        $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('pass'));
387
388        $worksheet->setBold('A' . $row . ':' . $worksheet->getColumnCoord($col - 1) . $row);
389
390        $counter = 1;
391        $data = $this->test_obj->getCompleteEvaluationData(true, $filterby, $filtertext);
392        $firstrowwritten = false;
393        foreach ($data->getParticipants() as $active_id => $userdata) {
394            if ($passedonly && $data->getParticipant($active_id)->getPassed() == false) {
395                continue;
396            }
397
398            $row++;
399            $col = 0;
400
401            // each participant gets an own row for question column headers
402            if ($this->test_obj->isRandomTest()) {
403                $row++;
404            }
405
406            if ($this->test_obj->getAnonymity()) {
407                $worksheet->setCell($row, $col++, $counter);
408            } else {
409                $worksheet->setCell($row, $col++, $data->getParticipant($active_id)->getName());
410                $worksheet->setCell($row, $col++, $data->getParticipant($active_id)->getLogin());
411            }
412
413            if (count($additionalFields)) {
414                $userfields = ilObjUser::_lookupFields($userdata->getUserId());
415                foreach ($additionalFields as $fieldname) {
416                    if (strcmp($fieldname, 'gender') == 0) {
417                        $worksheet->setCell($row, $col++, $this->lng->txt('gender_' . $userfields[$fieldname]));
418                    } elseif (strcmp($fieldname, "exam_id") == 0) {
419                        $worksheet->setCell($row, $col++, $userdata->getExamIdFromScoredPass());
420                    } else {
421                        $worksheet->setCell($row, $col++, $userfields[$fieldname]);
422                    }
423                }
424            }
425
426            $worksheet->setCell($row, $col++, $data->getParticipant($active_id)->getReached());
427            $worksheet->setCell($row, $col++, $data->getParticipant($active_id)->getMaxpoints());
428            $worksheet->setCell($row, $col++, $data->getParticipant($active_id)->getMark());
429
430            if ($this->test_obj->getECTSOutput()) {
431                $worksheet->setCell($row, $col++, $data->getParticipant($active_id)->getECTSMark());
432            }
433
434            $worksheet->setCell($row, $col++, $data->getParticipant($active_id)->getQuestionsWorkedThrough());
435            $worksheet->setCell($row, $col++, $data->getParticipant($active_id)->getNumberOfQuestions());
436            $worksheet->setCell($row, $col++, $data->getParticipant($active_id)->getQuestionsWorkedThroughInPercent() . '%');
437
438            $time = $data->getParticipant($active_id)->getTimeOfWork();
439            $time_seconds = $time;
440            $time_hours = floor($time_seconds / 3600);
441            $time_seconds -= $time_hours * 3600;
442            $time_minutes = floor($time_seconds / 60);
443            $time_seconds -= $time_minutes * 60;
444            $worksheet->setCell($row, $col++, sprintf("%02d:%02d:%02d", $time_hours, $time_minutes, $time_seconds));
445            $time = $data->getParticipant($active_id)->getQuestionsWorkedThrough() ? $data->getParticipant($active_id)->getTimeOfWork() / $data->getParticipant($active_id)->getQuestionsWorkedThrough() : 0;
446            $time_seconds = $time;
447            $time_hours = floor($time_seconds / 3600);
448            $time_seconds -= $time_hours * 3600;
449            $time_minutes = floor($time_seconds / 60);
450            $time_seconds -= $time_minutes * 60;
451            $worksheet->setCell($row, $col++, sprintf("%02d:%02d:%02d", $time_hours, $time_minutes, $time_seconds));
452            $worksheet->setCell($row, $col++, new ilDateTime($data->getParticipant($active_id)->getFirstVisit(), IL_CAL_UNIX));
453            $worksheet->setCell($row, $col++, new ilDateTime($data->getParticipant($active_id)->getLastVisit(), IL_CAL_UNIX));
454
455            $median = $data->getStatistics()->getStatistics()->median();
456            $pct = $data->getParticipant($active_id)->getMaxpoints() ? $median / $data->getParticipant($active_id)->getMaxpoints() * 100.0 : 0;
457            $mark = $this->test_obj->mark_schema->getMatchingMark($pct);
458            $mark_short_name = "";
459
460            if (is_object($mark)) {
461                $mark_short_name = $mark->getShortName();
462            }
463
464            $worksheet->setCell($row, $col++, $mark_short_name);
465            $worksheet->setCell($row, $col++, $data->getStatistics()->getStatistics()->rank($data->getParticipant($active_id)->getReached()));
466            $worksheet->setCell($row, $col++, $data->getStatistics()->getStatistics()->rank_median());
467            $worksheet->setCell($row, $col++, $data->getStatistics()->getStatistics()->count());
468            $worksheet->setCell($row, $col++, $median);
469
470            if ($this->test_obj->getPassScoring() == SCORE_BEST_PASS) {
471                $worksheet->setCell($row, $col++, $data->getParticipant($active_id)->getBestPass() + 1);
472            } else {
473                $worksheet->setCell($row, $col++, $data->getParticipant($active_id)->getLastPass() + 1);
474            }
475
476            $startcol = $col;
477
478            for ($pass = 0; $pass <= $data->getParticipant($active_id)->getLastPass(); $pass++) {
479                $col = $startcol;
480                $finishdate = ilObjTest::lookupPassResultsUpdateTimestamp($active_id, $pass);
481                if ($finishdate > 0) {
482                    if ($pass > 0) {
483                        $row++;
484                        if ($this->test_obj->isRandomTest()) {
485                            $row++;
486                        }
487                    }
488                    $worksheet->setCell($row, $col++, $pass + 1);
489                    if (is_object($data->getParticipant($active_id)) && is_array($data->getParticipant($active_id)->getQuestions($pass))) {
490                        $evaluatedQuestions = $data->getParticipant($active_id)->getQuestions($pass);
491
492                        if ($this->test_obj->getShuffleQuestions()) {
493                            // reorder questions according to general fixed sequence,
494                            // so participant rows can share single questions header
495                            $questions = array();
496                            foreach ($this->test_obj->getQuestions() as $qId) {
497                                foreach ($evaluatedQuestions as $evaledQst) {
498                                    if ($evaledQst['id'] != $qId) {
499                                        continue;
500                                    }
501
502                                    $questions[] = $evaledQst;
503                                }
504                            }
505                        } else {
506                            $questions = $evaluatedQuestions;
507                        }
508
509                        foreach ($questions as $question) {
510                            $question_data = $data->getParticipant($active_id)->getPass($pass)->getAnsweredQuestionByQuestionId($question["id"]);
511                            $worksheet->setCell($row, $col, $question_data["reached"]);
512                            if ($this->test_obj->isRandomTest()) {
513                                // random test requires question headers for every participant
514                                // and we allready skipped a row for that reason ( --> row - 1)
515                                $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col) . ($row - 1), preg_replace("/<.*?>/", "", $data->getQuestionTitle($question["id"])));
516                            } else {
517                                if ($pass == 0 && !$firstrowwritten) {
518                                    $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col) . 1, $data->getQuestionTitle($question["id"]));
519                                }
520                            }
521                            $col++;
522                        }
523                        $firstrowwritten = true;
524                    }
525                }
526            }
527            $counter++;
528        }
529
530        if ($this->test_obj->getExportSettingsSingleChoiceShort() && !$this->test_obj->isRandomTest() && $this->test_obj->hasSingleChoiceQuestions()) {
531            // special tab for single choice tests
532            $titles = $this->test_obj->getQuestionTitlesAndIndexes();
533            $positions = array();
534            $pos = 0;
535            $row = 1;
536            foreach ($titles as $id => $title) {
537                $positions[$id] = $pos;
538                $pos++;
539            }
540
541            $usernames = array();
542            $participantcount = count($data->getParticipants());
543            $allusersheet = false;
544            $pages = 0;
545
546            $worksheet->addSheet($this->lng->txt('eval_all_users'));
547
548            $col = 0;
549            $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('name'));
550            $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('login'));
551            if (count($additionalFields)) {
552                foreach ($additionalFields as $fieldname) {
553                    if (strcmp($fieldname, "matriculation") == 0) {
554                        $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('matriculation'));
555                    }
556                    if (strcmp($fieldname, "exam_id") == 0) {
557                        $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('exam_id_label'));
558                    }
559                }
560            }
561            $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('test'));
562            foreach ($titles as $title) {
563                $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $title);
564            }
565            $worksheet->setBold('A' . $row . ':' . $worksheet->getColumnCoord($col - 1) . $row);
566
567            $row++;
568            foreach ($data->getParticipants() as $active_id => $userdata) {
569                $username = (!is_null($userdata) && $userdata->getName()) ? $userdata->getName() : "ID $active_id";
570                if (array_key_exists($username, $usernames)) {
571                    $usernames[$username]++;
572                    $username .= " ($usernames[$username])";
573                } else {
574                    $usernames[$username] = 1;
575                }
576                $col = 0;
577                $worksheet->setCell($row, $col++, $username);
578                $worksheet->setCell($row, $col++, $userdata->getLogin());
579                if (count($additionalFields)) {
580                    $userfields = ilObjUser::_lookupFields($userdata->getUserID());
581                    foreach ($additionalFields as $fieldname) {
582                        if (strcmp($fieldname, "matriculation") == 0) {
583                            if (strlen($userfields[$fieldname])) {
584                                $worksheet->setCell($row, $col++, $userfields[$fieldname]);
585                            } else {
586                                $col++;
587                            }
588                        }
589                        if (strcmp($fieldname, "exam_id") == 0) {
590                            if (strlen($userfields[$fieldname])) {
591                                $worksheet->setCell($row, $col++, $userdata->getExamIdFromScoredPass());
592                            } else {
593                                $col++;
594                            }
595                        }
596                    }
597                }
598                $worksheet->setCell($row, $col++, $this->test_obj->getTitle());
599                $pass = $userdata->getScoredPass();
600                if (is_object($userdata) && is_array($userdata->getQuestions($pass))) {
601                    foreach ($userdata->getQuestions($pass) as $question) {
602                        $objQuestion = assQuestion::_instantiateQuestion($question["id"]);
603                        if (is_object($objQuestion) && strcmp($objQuestion->getQuestionType(), 'assSingleChoice') == 0) {
604                            $solution = $objQuestion->getSolutionValues($active_id, $pass);
605                            $pos = $positions[$question["id"]];
606                            $selectedanswer = "x";
607                            foreach ($objQuestion->getAnswers() as $id => $answer) {
608                                if (strlen($solution[0]["value1"]) && $id == $solution[0]["value1"]) {
609                                    $selectedanswer = $answer->getAnswertext();
610                                }
611                            }
612                            $worksheet->setCell($row, $col + $pos, $selectedanswer);
613                        }
614                    }
615                }
616                $row++;
617            }
618
619            if ($this->test_obj->isSingleChoiceTestWithoutShuffle()) {
620                // special tab for single choice tests without shuffle option
621                $pos = 0;
622                $row = 1;
623                $usernames = array();
624                $allusersheet = false;
625                $pages = 0;
626
627                $worksheet->addSheet($this->lng->txt('eval_all_users') . ' (2)');
628
629                $col = 0;
630                $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('name'));
631                $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('login'));
632                if (count($additionalFields)) {
633                    foreach ($additionalFields as $fieldname) {
634                        if (strcmp($fieldname, "matriculation") == 0) {
635                            $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('matriculation'));
636                        }
637                        if (strcmp($fieldname, "exam_id") == 0) {
638                            $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('exam_id_label'));
639                        }
640                    }
641                }
642                $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $this->lng->txt('test'));
643                foreach ($titles as $title) {
644                    $worksheet->setFormattedExcelTitle($worksheet->getColumnCoord($col++) . $row, $title);
645                }
646                $worksheet->setBold('A' . $row . ':' . $worksheet->getColumnCoord($col - 1) . $row);
647
648                $row++;
649                foreach ($data->getParticipants() as $active_id => $userdata) {
650                    $username = (!is_null($userdata) && $userdata->getName()) ? $userdata->getName() : "ID $active_id";
651                    if (array_key_exists($username, $usernames)) {
652                        $usernames[$username]++;
653                        $username .= " ($usernames[$username])";
654                    } else {
655                        $usernames[$username] = 1;
656                    }
657                    $col = 0;
658                    $worksheet->setCell($row, $col++, $username);
659                    $worksheet->setCell($row, $col++, $userdata->getLogin());
660                    if (count($additionalFields)) {
661                        $userfields = ilObjUser::_lookupFields($userdata->getUserId());
662                        foreach ($additionalFields as $fieldname) {
663                            if (strcmp($fieldname, "matriculation") == 0) {
664                                if (strlen($userfields[$fieldname])) {
665                                    $worksheet->setCell($row, $col++, $userfields[$fieldname]);
666                                } else {
667                                    $col++;
668                                }
669                            }
670                            if (strcmp($fieldname, "exam_id") == 0) {
671                                if (strlen($userfields[$fieldname])) {
672                                    $worksheet->setCell($row, $col++, $userdata->getExamIdFromScoredPass());
673                                } else {
674                                    $col++;
675                                }
676                            }
677                        }
678                    }
679                    $worksheet->setCell($row, $col++, $this->test_obj->getTitle());
680                    $pass = $userdata->getScoredPass();
681                    if (is_object($userdata) && is_array($userdata->getQuestions($pass))) {
682                        foreach ($userdata->getQuestions($pass) as $question) {
683                            $objQuestion = ilObjTest::_instanciateQuestion($question["aid"]);
684                            if (is_object($objQuestion) && strcmp($objQuestion->getQuestionType(), 'assSingleChoice') == 0) {
685                                $solution = $objQuestion->getSolutionValues($active_id, $pass);
686                                $pos = $positions[$question["aid"]];
687                                $selectedanswer = chr(65 + $solution[0]["value1"]);
688                                $worksheet->setCell($row, $col + $pos, $selectedanswer);
689                            }
690                        }
691                    }
692                    $row++;
693                }
694            }
695        } else {
696            // test participant result export
697            $usernames = array();
698            $participantcount = count($data->getParticipants());
699            $allusersheet = false;
700            $pages = 0;
701            $i = 0;
702            foreach ($data->getParticipants() as $active_id => $userdata) {
703                $i++;
704
705                $username = (!is_null($userdata) && $userdata->getName()) ? $userdata->getName() : "ID $active_id";
706                if (array_key_exists($username, $usernames)) {
707                    $usernames[$username]++;
708                    $username .= " ($i)";
709                } else {
710                    $usernames[$username] = 1;
711                }
712
713                if ($participantcount > 250) {
714                    if (!$allusersheet || ($pages - 1) < floor($row / 64000)) {
715                        $worksheet->addSheet($this->lng->txt("eval_all_users") . (($pages > 0) ? " (" . ($pages + 1) . ")" : ""));
716                        $allusersheet = true;
717                        $row = 1;
718                        $pages++;
719                    }
720                } else {
721                    $resultsheet = $worksheet->addSheet($username);
722                }
723
724                $pass = $userdata->getScoredPass();
725                $row = ($allusersheet) ? $row : 1;
726                $worksheet->setCell($row, 0, sprintf($this->lng->txt("tst_result_user_name_pass"), $pass + 1, $userdata->getName()));
727                $worksheet->setBold($worksheet->getColumnCoord(0) . $row);
728                $row += 2;
729                if (is_object($userdata) && is_array($userdata->getQuestions($pass))) {
730                    foreach ($userdata->getQuestions($pass) as $question) {
731                        require_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
732                        $question = assQuestion::_instanciateQuestion($question["id"]);
733                        if (is_object($question)) {
734                            $row = $question->setExportDetailsXLS($worksheet, $row, $active_id, $pass);
735                        }
736                    }
737                }
738            }
739        }
740
741        if ($deliver) {
742            $testname = $this->test_obj->getTitle();
743            switch ($this->mode) {
744                case 'results':
745                    $testname .= '_results';
746                    break;
747            }
748            $testname = ilUtil::getASCIIFilename(preg_replace("/\s/", "_", $testname)) . '.xlsx';
749            $worksheet->sendToClient($testname);
750        } else {
751            $excelfile = ilUtil::ilTempnam();
752            $worksheet->writeToFile($excelfile);
753            return $excelfile . '.xlsx';
754        }
755    }
756
757
758
759    /**
760    * Exports the evaluation data to the CSV file format
761    *
762    * Exports the evaluation data to the CSV file format
763    *
764    * @param string $filtertext Filter text for the user data
765    * @param boolean $passedonly TRUE if only passed user datasets should be exported, FALSE otherwise
766    * @access public
767    */
768    public function exportToCSV($deliver = true, $filterby = "", $filtertext = "", $passedonly = false)
769    {
770        $this->test_obj->setAccessFilteredParticipantList(
771            $this->test_obj->buildStatisticsAccessFilteredParticipantList()
772        );
773
774        if (strcmp($this->mode, "aggregated") == 0) {
775            return $this->aggregatedResultsToCSV($deliver);
776        }
777
778        $rows = array();
779        $datarow = array();
780        $col = 1;
781        if ($this->test_obj->getAnonymity()) {
782            array_push($datarow, $this->lng->txt("counter"));
783            $col++;
784        } else {
785            array_push($datarow, $this->lng->txt("name"));
786            $col++;
787            array_push($datarow, $this->lng->txt("login"));
788            $col++;
789        }
790        $additionalFields = $this->test_obj->getEvaluationAdditionalFields();
791        if (count($additionalFields)) {
792            foreach ($additionalFields as $fieldname) {
793                if (strcmp($fieldname, "exam_id") == 0) {
794                    array_push($datarow, $this->lng->txt('exam_id_label'));
795                    $col++;
796                    continue;
797                }
798                array_push($datarow, $this->lng->txt($fieldname));
799                $col++;
800            }
801        }
802        array_push($datarow, $this->lng->txt("tst_stat_result_resultspoints"));
803        $col++;
804        array_push($datarow, $this->lng->txt("maximum_points"));
805        $col++;
806        array_push($datarow, $this->lng->txt("tst_stat_result_resultsmarks"));
807        $col++;
808        if ($this->test_obj->getECTSOutput()) {
809            array_push($datarow, $this->lng->txt("ects_grade"));
810            $col++;
811        }
812        array_push($datarow, $this->lng->txt("tst_stat_result_qworkedthrough"));
813        $col++;
814        array_push($datarow, $this->lng->txt("tst_stat_result_qmax"));
815        $col++;
816        array_push($datarow, $this->lng->txt("tst_stat_result_pworkedthrough"));
817        $col++;
818        array_push($datarow, $this->lng->txt("tst_stat_result_timeofwork"));
819        $col++;
820        array_push($datarow, $this->lng->txt("tst_stat_result_atimeofwork"));
821        $col++;
822        array_push($datarow, $this->lng->txt("tst_stat_result_firstvisit"));
823        $col++;
824        array_push($datarow, $this->lng->txt("tst_stat_result_lastvisit"));
825        $col++;
826
827        array_push($datarow, $this->lng->txt("tst_stat_result_mark_median"));
828        $col++;
829        array_push($datarow, $this->lng->txt("tst_stat_result_rank_participant"));
830        $col++;
831        array_push($datarow, $this->lng->txt("tst_stat_result_rank_median"));
832        $col++;
833        array_push($datarow, $this->lng->txt("tst_stat_result_total_participants"));
834        $col++;
835        array_push($datarow, $this->lng->txt("tst_stat_result_median"));
836        $col++;
837        array_push($datarow, $this->lng->txt("scored_pass"));
838        $col++;
839
840        array_push($datarow, $this->lng->txt("pass"));
841        $col++;
842
843        $data = &$this->test_obj->getCompleteEvaluationData(true, $filterby, $filtertext);
844        $headerrow = $datarow;
845        $counter = 1;
846        foreach ($data->getParticipants() as $active_id => $userdata) {
847            $datarow = $headerrow;
848            $remove = false;
849            if ($passedonly) {
850                if ($data->getParticipant($active_id)->getPassed() == false) {
851                    $remove = true;
852                }
853            }
854            if (!$remove) {
855                $datarow2 = array();
856                if ($this->test_obj->getAnonymity()) {
857                    array_push($datarow2, $counter);
858                } else {
859                    array_push($datarow2, $data->getParticipant($active_id)->getName());
860                    array_push($datarow2, $data->getParticipant($active_id)->getLogin());
861                }
862                if (count($additionalFields)) {
863                    $userfields = ilObjUser::_lookupFields($userdata->getUserID());
864                    foreach ($additionalFields as $fieldname) {
865                        if (strcmp($fieldname, "gender") == 0) {
866                            array_push($datarow2, $this->lng->txt("gender_" . $userfields[$fieldname]));
867                        } elseif (strcmp($fieldname, "exam_id") == 0) {
868                            array_push($datarow2, $userdata->getExamIdFromScoredPass());
869                        } else {
870                            array_push($datarow2, $userfields[$fieldname]);
871                        }
872                    }
873                }
874                array_push($datarow2, $data->getParticipant($active_id)->getReached());
875                array_push($datarow2, $data->getParticipant($active_id)->getMaxpoints());
876                array_push($datarow2, $data->getParticipant($active_id)->getMark());
877                if ($this->test_obj->getECTSOutput()) {
878                    array_push($datarow2, $data->getParticipant($active_id)->getECTSMark());
879                }
880                array_push($datarow2, $data->getParticipant($active_id)->getQuestionsWorkedThrough());
881                array_push($datarow2, $data->getParticipant($active_id)->getNumberOfQuestions());
882                array_push($datarow2, $data->getParticipant($active_id)->getQuestionsWorkedThroughInPercent() / 100.0);
883                $time = $data->getParticipant($active_id)->getTimeOfWork();
884                $time_seconds = $time;
885                $time_hours = floor($time_seconds / 3600);
886                $time_seconds -= $time_hours * 3600;
887                $time_minutes = floor($time_seconds / 60);
888                $time_seconds -= $time_minutes * 60;
889                array_push($datarow2, sprintf("%02d:%02d:%02d", $time_hours, $time_minutes, $time_seconds));
890                $time = $data->getParticipant($active_id)->getQuestionsWorkedThrough() ? $data->getParticipant($active_id)->getTimeOfWork() / $data->getParticipant($active_id)->getQuestionsWorkedThrough() : 0;
891                $time_seconds = $time;
892                $time_hours = floor($time_seconds / 3600);
893                $time_seconds -= $time_hours * 3600;
894                $time_minutes = floor($time_seconds / 60);
895                $time_seconds -= $time_minutes * 60;
896                array_push($datarow2, sprintf("%02d:%02d:%02d", $time_hours, $time_minutes, $time_seconds));
897
898                $fv = $data->getParticipant($active_id)->getFirstVisit();
899                $lv = $data->getParticipant($active_id)->getLastVisit();
900                foreach (array($fv, $lv) as $ts) {
901                    if ($ts) {
902                        $visit = ilDatePresentation::formatDate(new ilDateTime($ts, IL_CAL_UNIX));
903                        array_push($datarow2, $visit);
904                    } else {
905                        array_push($datarow2, "");
906                    }
907                }
908
909                $median = $data->getStatistics()->getStatistics()->median();
910                $pct = $data->getParticipant($active_id)->getMaxpoints() ? $median / $data->getParticipant($active_id)->getMaxpoints() * 100.0 : 0;
911                $mark = $this->test_obj->mark_schema->getMatchingMark($pct);
912                $mark_short_name = "";
913                if (is_object($mark)) {
914                    $mark_short_name = $mark->getShortName();
915                }
916                array_push($datarow2, $mark_short_name);
917                array_push($datarow2, $data->getStatistics()->getStatistics()->rank($data->getParticipant($active_id)->getReached()));
918                array_push($datarow2, $data->getStatistics()->getStatistics()->rank_median());
919                array_push($datarow2, $data->getStatistics()->getStatistics()->count());
920                array_push($datarow2, $median);
921                if ($this->test_obj->getPassScoring() == SCORE_BEST_PASS) {
922                    array_push($datarow2, $data->getParticipant($active_id)->getBestPass() + 1);
923                } else {
924                    array_push($datarow2, $data->getParticipant($active_id)->getLastPass() + 1);
925                }
926                for ($pass = 0; $pass <= $data->getParticipant($active_id)->getLastPass(); $pass++) {
927                    $finishdate = ilObjTest::lookupPassResultsUpdateTimestamp($active_id, $pass);
928                    if ($finishdate > 0) {
929                        if ($pass > 0) {
930                            for ($i = 1; $i < $col - 1; $i++) {
931                                array_push($datarow2, "");
932                                array_push($datarow, "");
933                            }
934                            array_push($datarow, "");
935                        }
936                        array_push($datarow2, $pass + 1);
937                        if (is_object($data->getParticipant($active_id)) && is_array($data->getParticipant($active_id)->getQuestions($pass))) {
938                            foreach ($data->getParticipant($active_id)->getQuestions($pass) as $question) {
939                                $question_data = $data->getParticipant($active_id)->getPass($pass)->getAnsweredQuestionByQuestionId($question["id"]);
940                                array_push($datarow2, $question_data["reached"]);
941                                array_push($datarow, preg_replace("/<.*?>/", "", $data->getQuestionTitle($question["id"])));
942                            }
943                        }
944                        if ($this->test_obj->isRandomTest() || $this->test_obj->getShuffleQuestions() || ($counter == 1 && $pass == 0)) {
945                            array_push($rows, $datarow);
946                        }
947                        $datarow = array();
948                        array_push($rows, $datarow2);
949                        $datarow2 = array();
950                    }
951                }
952                $counter++;
953            }
954        }
955        $csv = "";
956        $separator = ";";
957        foreach ($rows as $evalrow) {
958            $csvrow = &$this->test_obj->processCSVRow($evalrow, true, $separator);
959            $csv .= join($separator, $csvrow) . "\n";
960        }
961        if ($deliver) {
962            ilUtil::deliverData($csv, ilUtil::getASCIIFilename($this->test_obj->getTitle() . "_results.csv"));
963            exit;
964        } else {
965            return $csv;
966        }
967    }
968
969    abstract protected function initXmlExport();
970
971    abstract protected function getQuestionIds();
972
973    /**
974    * build xml export file
975    */
976    public function buildExportFileXML()
977    {
978        global $DIC;
979        $ilBench = $DIC['ilBench'];
980
981        $ilBench->start("TestExport", "buildExportFile");
982
983        $this->initXmlExport();
984
985        include_once("./Services/Xml/classes/class.ilXmlWriter.php");
986        $this->xml = new ilXmlWriter;
987
988        // set dtd definition
989        $this->xml->xmlSetDtdDef("<!DOCTYPE Test SYSTEM \"http://www.ilias.uni-koeln.de/download/dtd/ilias_co.dtd\">");
990
991        // set generated comment
992        $this->xml->xmlSetGenCmt("Export of ILIAS Test " .
993            $this->test_obj->getId() . " of installation " . $this->inst . ".");
994
995        // set xml header
996        $this->xml->xmlHeader();
997
998        $this->xml->xmlStartTag("ContentObject", array('Type' => 'Test'));
999
1000        // create directories
1001        $this->test_obj->createExportDirectory();
1002        include_once "./Services/Utilities/classes/class.ilUtil.php";
1003        ilUtil::makeDir($this->export_dir . "/" . $this->subdir);
1004        ilUtil::makeDir($this->export_dir . "/" . $this->subdir . "/objects");
1005
1006        // get Log File
1007        $expDir = $this->test_obj->getExportDirectory();
1008        include_once "./Services/Logging/classes/class.ilLog.php";
1009        $expLog = new ilLog($expDir, "export.log");
1010        $expLog->delete();
1011        $expLog->setLogFormat("");
1012        $expLog->write(date("[y-m-d H:i:s] ") . "Start Export");
1013
1014        // write qti file
1015        $qti_file = fopen($this->export_dir . "/" . $this->subdir . "/" . $this->qti_filename, "w");
1016        fwrite($qti_file, $this->getQtiXml());
1017        fclose($qti_file);
1018
1019        // get xml content
1020        $ilBench->start("TestExport", "buildExportFile_getXML");
1021        $this->test_obj->exportPagesXML(
1022            $this->xml,
1023            $this->inst_id,
1024            $this->export_dir . "/" . $this->subdir,
1025            $expLog
1026        );
1027        $ilBench->stop("TestExport", "buildExportFile_getXML");
1028
1029        $this->populateQuestionSetConfigXml($this->xml);
1030
1031        $assignmentList = $this->buildQuestionSkillAssignmentList();
1032        $this->populateQuestionSkillAssignmentsXml($this->xml, $assignmentList, $this->getQuestionIds());
1033        $this->populateSkillLevelThresholdsXml($this->xml, $assignmentList);
1034
1035        $this->xml->xmlEndTag("ContentObject");
1036
1037        // dump xml document to screen (only for debugging reasons)
1038        /*
1039        echo "<PRE>";
1040        echo htmlentities($this->xml->xmlDumpMem($format));
1041        echo "</PRE>";
1042        */
1043
1044        // dump xml document to file
1045        $ilBench->start("TestExport", "buildExportFile_dumpToFile");
1046        $this->xml->xmlDumpFile($this->export_dir . "/" . $this->subdir . "/" . $this->filename, false);
1047        $ilBench->stop("TestExport", "buildExportFile_dumpToFile");
1048
1049        if ($this->isResultExportingEnabledForTestExport() && @file_exists("./Modules/Test/classes/class.ilTestResultsToXML.php")) {
1050            // dump results xml document to file
1051            include_once "./Modules/Test/classes/class.ilTestResultsToXML.php";
1052            $resultwriter = new ilTestResultsToXML($this->test_obj->getTestId(), $this->test_obj->getAnonymity());
1053            $resultwriter->setIncludeRandomTestQuestionsEnabled($this->test_obj->isRandomTest());
1054            $ilBench->start("TestExport", "buildExportFile_results");
1055            $resultwriter->xmlDumpFile($this->export_dir . "/" . $this->subdir . "/" . $this->resultsfile, false);
1056            $ilBench->stop("TestExport", "buildExportFile_results");
1057        }
1058
1059        // add media objects which were added with tiny mce
1060        $ilBench->start("QuestionpoolExport", "buildExportFile_saveAdditionalMobs");
1061        $this->exportXHTMLMediaObjects($this->export_dir . "/" . $this->subdir);
1062        $ilBench->stop("QuestionpoolExport", "buildExportFile_saveAdditionalMobs");
1063
1064        // zip the file
1065        $ilBench->start("TestExport", "buildExportFile_zipFile");
1066        ilUtil::zip(
1067            $this->export_dir . "/" . $this->subdir,
1068            $this->export_dir . "/" . $this->subdir . ".zip"
1069        );
1070        $ilBench->stop("TestExport", "buildExportFile_zipFile");
1071
1072        // destroy writer object
1073        $this->xml->_XmlWriter;
1074
1075        $expLog->write(date("[y-m-d H:i:s] ") . "Finished Export");
1076        $ilBench->stop("TestExport", "buildExportFile");
1077
1078        return $this->export_dir . "/" . $this->subdir . ".zip";
1079    }
1080
1081    abstract protected function populateQuestionSetConfigXml(ilXmlWriter $xmlWriter);
1082
1083    protected function getQtiXml()
1084    {
1085        $tstQtiXml = $this->test_obj->toXML();
1086        $qstQtiXml = $this->getQuestionsQtiXml();
1087
1088        if (strpos($tstQtiXml, "</section>") !== false) {
1089            $qtiXml = str_replace("</section>", "$qstQtiXml</section>", $tstQtiXml);
1090        } else {
1091            $qtiXml = str_replace("<section ident=\"1\"/>", "<section ident=\"1\">\n$qstQtiXml</section>", $tstQtiXml);
1092        }
1093
1094        return $qtiXml;
1095    }
1096
1097    abstract protected function getQuestionsQtiXml();
1098
1099    protected function getQuestionQtiXml($questionId)
1100    {
1101        include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
1102        $questionOBJ = assQuestion::_instantiateQuestion($questionId);
1103        $xml = $questionOBJ->toXML(false);
1104
1105        // still neccessary? there is an include header flag!?
1106        $xml = preg_replace("/<questestinterop>/", "", $xml);
1107        $xml = preg_replace("/<\/questestinterop>/", "", $xml);
1108
1109        return $xml;
1110    }
1111
1112    public function exportXHTMLMediaObjects($a_export_dir)
1113    {
1114        include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
1115
1116        $mobs = ilObjMediaObject::_getMobsOfObject("tst:html", $this->test_obj->getId());
1117        foreach ($mobs as $mob) {
1118            if (ilObjMediaObject::_exists($mob)) {
1119                $mob_obj = new ilObjMediaObject($mob);
1120                $mob_obj->exportFiles($a_export_dir);
1121                unset($mob_obj);
1122            }
1123        }
1124        foreach ($this->getQuestionIds() as $question_id) {
1125            $mobs = ilObjMediaObject::_getMobsOfObject("qpl:html", $question_id);
1126            foreach ($mobs as $mob) {
1127                if (ilObjMediaObject::_exists($mob)) {
1128                    $mob_obj = new ilObjMediaObject($mob);
1129                    $mob_obj->exportFiles($a_export_dir);
1130                    unset($mob_obj);
1131                }
1132            }
1133        }
1134    }
1135
1136    /**
1137     * @param ilXmlWriter $a_xml_writer
1138     * @param $questions
1139     */
1140    protected function populateQuestionSkillAssignmentsXml(ilXmlWriter $a_xml_writer, ilAssQuestionSkillAssignmentList $assignmentList, $questions)
1141    {
1142        require_once 'Modules/TestQuestionPool/classes/questions/class.ilAssQuestionSkillAssignmentExporter.php';
1143        $skillQuestionAssignmentExporter = new ilAssQuestionSkillAssignmentExporter();
1144        $skillQuestionAssignmentExporter->setXmlWriter($a_xml_writer);
1145        $skillQuestionAssignmentExporter->setQuestionIds($questions);
1146        $skillQuestionAssignmentExporter->setAssignmentList($assignmentList);
1147        $skillQuestionAssignmentExporter->export();
1148    }
1149
1150    protected function populateSkillLevelThresholdsXml(ilXmlWriter $a_xml_writer, ilAssQuestionSkillAssignmentList $assignmentList)
1151    {
1152        global $DIC;
1153        $ilDB = $DIC['ilDB'];
1154
1155        require_once 'Modules/Test/classes/class.ilTestSkillLevelThresholdList.php';
1156        $thresholdList = new ilTestSkillLevelThresholdList($ilDB);
1157        $thresholdList->setTestId($this->test_obj->getTestId());
1158        $thresholdList->loadFromDb();
1159
1160        require_once 'Modules/Test/classes/class.ilTestSkillLevelThresholdExporter.php';
1161        $skillLevelThresholdExporter = new ilTestSkillLevelThresholdExporter();
1162        $skillLevelThresholdExporter->setXmlWriter($a_xml_writer);
1163        $skillLevelThresholdExporter->setAssignmentList($assignmentList);
1164        $skillLevelThresholdExporter->setThresholdList($thresholdList);
1165        $skillLevelThresholdExporter->export();
1166    }
1167
1168    /**
1169     * @return ilAssQuestionSkillAssignmentList
1170     */
1171    protected function buildQuestionSkillAssignmentList()
1172    {
1173        global $DIC;
1174        $ilDB = $DIC['ilDB'];
1175
1176        require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionSkillAssignmentList.php';
1177        $assignmentList = new ilAssQuestionSkillAssignmentList($ilDB);
1178        $assignmentList->setParentObjId($this->test_obj->getId());
1179        $assignmentList->loadFromDb();
1180        $assignmentList->loadAdditionalSkillData();
1181
1182        return $assignmentList;
1183    }
1184}
1185