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