1<?php
2/* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4include_once "./Modules/Test/classes/inc.AssessmentConstants.php";
5include_once 'Modules/Test/classes/class.ilTestService.php';
6
7/**
8* Service GUI class for tests. This class is the parent class for all
9* service classes which are called from ilObjTestGUI. This is mainly
10* done to reduce the size of ilObjTestGUI to put command service functions
11* into classes that could be called by ilCtrl.
12*
13* @ilCtrl_IsCalledBy ilTestServiceGUI: ilObjTestGUI
14*
15* @author	Helmut Schottmüller <helmut.schottmueller@mac.com>
16* @author	Björn Heyser <bheyser@databay.de>
17* @version	$Id$
18*
19* @ingroup ModulesTest
20*/
21class ilTestServiceGUI
22{
23    /**
24     * @var ilObjTest
25     */
26    public $object = null;
27
28    /**
29     * @var ilTestService
30     */
31    public $service = null;
32
33    /**
34     * @var ilDBInterface
35     */
36    protected $db;
37
38    public $lng;
39    /** @var ilGlobalTemplateInterface */
40    public $tpl;
41
42    /**
43     * @var ilCtrl
44     */
45    public $ctrl;
46
47    /**
48     * @var ilTabsGUI
49     */
50    protected $tabs;
51
52    /**
53     * @var ilObjectDataCache
54     */
55    protected $objCache;
56
57    public $ilias;
58    public $tree;
59    public $ref_id;
60
61    /**
62     * factory for test session
63     *
64     * @var ilTestSessionFactory
65     */
66    protected $testSessionFactory = null;
67
68    /**
69     * factory for test sequence
70     *
71     * @var ilTestSequenceFactory
72     */
73    protected $testSequenceFactory = null;
74
75    /**
76     * @var ilTestParticipantData
77     */
78    protected $participantData;
79
80    /**
81     * @var ilTestObjectiveOrientedContainer
82     */
83    private $objectiveOrientedContainer;
84
85    private $contextResultPresentation = true;
86
87    /**
88     * @return boolean
89     */
90    public function isContextResultPresentation()
91    {
92        return $this->contextResultPresentation;
93    }
94
95    /**
96     * @param boolean $contextResultPresentation
97     */
98    public function setContextResultPresentation($contextResultPresentation)
99    {
100        $this->contextResultPresentation = $contextResultPresentation;
101    }
102
103    /**
104     * The constructor takes the test object reference as parameter
105     *
106     * @param object $a_object Associated ilObjTest class
107     * @access public
108     */
109    public function __construct(ilObjTest $a_object)
110    {
111        global $DIC;
112        $lng = $DIC['lng'];
113        $tpl = $DIC['tpl'];
114        $ilCtrl = $DIC['ilCtrl'];
115        $ilias = $DIC['ilias'];
116        $tree = $DIC['tree'];
117        $ilDB = $DIC['ilDB'];
118        $ilPluginAdmin = $DIC['ilPluginAdmin'];
119        $ilTabs = $DIC['ilTabs'];
120        $ilObjDataCache = $DIC['ilObjDataCache'];
121
122        $lng->loadLanguageModule('cert');
123
124        $this->db = $ilDB;
125        $this->lng = &$lng;
126        $this->tpl = &$tpl;
127        $this->ctrl = &$ilCtrl;
128        $this->tabs = $ilTabs;
129        $this->objCache = $ilObjDataCache;
130        $this->ilias = &$ilias;
131        $this->object = &$a_object;
132        $this->tree = &$tree;
133        $this->ref_id = $a_object->ref_id;
134
135        $this->service = new ilTestService($a_object);
136
137        require_once 'Modules/Test/classes/class.ilTestSessionFactory.php';
138        $this->testSessionFactory = new ilTestSessionFactory($this->object);
139
140        require_once 'Modules/Test/classes/class.ilTestSequenceFactory.php';
141        $this->testSequenceFactory = new ilTestSequenceFactory($ilDB, $lng, $ilPluginAdmin, $this->object);
142
143        $this->objectiveOrientedContainer = null;
144    }
145
146    /**
147     * @param \ilTestParticipantData $participantData
148     */
149    public function setParticipantData($participantData)
150    {
151        $this->participantData = $participantData;
152    }
153
154    /**
155     * @return \ilTestParticipantData
156     */
157    public function getParticipantData()
158    {
159        return $this->participantData;
160    }
161
162    /**
163     * @param ilTestSession $testSession
164     * @param $short
165     * @return array
166     */
167    public function getPassOverviewTableData(ilTestSession $testSession, $passes, $withResults)
168    {
169        $data = array();
170
171        if ($this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired()) {
172            $considerHiddenQuestions = false;
173
174            require_once 'Modules/Course/classes/Objectives/class.ilLOTestQuestionAdapter.php';
175            $objectivesAdapter = ilLOTestQuestionAdapter::getInstance($testSession);
176        } else {
177            $considerHiddenQuestions = true;
178        }
179
180        $scoredPass = $this->object->_getResultPass($testSession->getActiveId());
181
182        require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionHintTracking.php';
183        $questionHintRequestRegister = ilAssQuestionHintTracking::getRequestRequestStatisticDataRegisterByActiveId(
184            $testSession->getActiveId()
185        );
186
187        foreach ($passes as $pass) {
188            $row = array();
189
190            $considerOptionalQuestions = true;
191
192            if ($this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired()) {
193                $testSequence = $this->testSequenceFactory->getSequenceByActiveIdAndPass($testSession->getActiveId(), $pass);
194
195                $testSequence->loadFromDb();
196                $testSequence->loadQuestions();
197
198                if ($this->object->isRandomTest() && !$testSequence->isAnsweringOptionalQuestionsConfirmed()) {
199                    $considerOptionalQuestions = false;
200                }
201
202                $testSequence->setConsiderHiddenQuestionsEnabled($considerHiddenQuestions);
203                $testSequence->setConsiderOptionalQuestionsEnabled($considerOptionalQuestions);
204
205                $objectivesList = $this->buildQuestionRelatedObjectivesList($objectivesAdapter, $testSequence);
206                $objectivesList->loadObjectivesTitles();
207
208                $row['objectives'] = $objectivesList->getUniqueObjectivesStringForQuestions($testSequence->getUserSequenceQuestions());
209            }
210
211            if ($withResults) {
212                $result_array = $this->object->getTestResult($testSession->getActiveId(), $pass, false, $considerHiddenQuestions, $considerOptionalQuestions);
213
214                foreach ($result_array as $resultStructKEY => $question) {
215                    if ($resultStructKEY === 'test' || $resultStructKEY === 'pass') {
216                        continue;
217                    }
218
219                    $requestData = $questionHintRequestRegister->getRequestByTestPassIndexAndQuestionId($pass, $question['qid']);
220
221                    if ($requestData instanceof ilAssQuestionHintRequestStatisticData && $result_array[$resultStructKEY]['requested_hints'] === null) {
222                        $result_array['pass']['total_requested_hints'] += $requestData->getRequestsCount();
223
224                        $result_array[$resultStructKEY]['requested_hints'] = $requestData->getRequestsCount();
225                        $result_array[$resultStructKEY]['hint_points'] = $requestData->getRequestsPoints();
226                    }
227                }
228
229                if (!$result_array['pass']['total_max_points']) {
230                    $percentage = 0;
231                } else {
232                    $percentage = ($result_array['pass']['total_reached_points'] / $result_array['pass']['total_max_points']) * 100;
233                }
234                $total_max = $result_array['pass']['total_max_points'];
235                $total_reached = $result_array['pass']['total_reached_points'];
236                $total_requested_hints = $result_array['pass']['total_requested_hints'];
237            }
238
239            if ($withResults) {
240                $row['scored'] = ($pass == $scoredPass);
241            }
242
243            $row['pass'] = $pass;
244            $row['date'] = ilObjTest::lookupLastTestPassAccess($testSession->getActiveId(), $pass);
245            if ($withResults) {
246                $row['num_workedthrough_questions'] = $result_array['pass']['num_workedthrough'];
247                $row['num_questions_total'] = $result_array['pass']['num_questions_total'];
248
249                if ($this->object->isOfferingQuestionHintsEnabled()) {
250                    $row['hints'] = $total_requested_hints;
251                }
252
253                $row['reached_points'] = $total_reached;
254                $row['max_points'] = $total_max;
255                $row['percentage'] = $percentage;
256            }
257
258            $data[] = $row;
259        }
260
261        return $data;
262    }
263
264    /**
265     * @param ilTestObjectiveOrientedContainer $objectiveOrientedContainer
266     */
267    public function setObjectiveOrientedContainer(ilTestObjectiveOrientedContainer $objectiveOrientedContainer)
268    {
269        $this->objectiveOrientedContainer = $objectiveOrientedContainer;
270    }
271
272    /**
273     * @return ilTestObjectiveOrientedContainer
274     */
275    public function getObjectiveOrientedContainer()
276    {
277        return $this->objectiveOrientedContainer;
278    }
279
280    /**
281     * execute command
282     */
283    public function executeCommand()
284    {
285        $cmd = $this->ctrl->getCmd();
286        $next_class = $this->ctrl->getNextClass($this);
287
288        $cmd = $this->getCommand($cmd);
289        switch ($next_class) {
290            default:
291                $ret = &$this->$cmd();
292                break;
293        }
294        return $ret;
295    }
296
297    /**
298     * Retrieves the ilCtrl command
299     *
300     * @access public
301     */
302    public function getCommand($cmd)
303    {
304        return $cmd;
305    }
306
307    /**
308     * @return bool
309     */
310    protected function isPdfDeliveryRequest()
311    {
312        if (!isset($_GET['pdf'])) {
313            return false;
314        }
315
316        if (!(bool) $_GET['pdf']) {
317            return false;
318        }
319
320        return true;
321    }
322
323    /**
324     * @return ilTestPassOverviewTableGUI $tableGUI
325     */
326    public function buildPassOverviewTableGUI($targetGUI)
327    {
328        require_once 'Modules/Test/classes/tables/class.ilTestPassOverviewTableGUI.php';
329
330        $table = new ilTestPassOverviewTableGUI($targetGUI, '');
331
332        $table->setPdfPresentationEnabled(
333            isset($_GET['pdf']) && $_GET['pdf'] == 1
334        );
335
336        $table->setObjectiveOrientedPresentationEnabled(
337            $this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired()
338        );
339
340        return $table;
341    }
342
343    /**
344     * Returns the list of answers of a users test pass
345     *
346     * @param array $result_array An array containing the results of the users test pass (generated by ilObjTest::getTestResult)
347     * @param integer $active_id Active ID of the active user
348     * @param integer $pass Test pass
349     * @param boolean $show_solutions TRUE, if the solution output should be shown in the answers, FALSE otherwise
350     * @return string HTML code of the list of answers
351     * @access public
352     */
353    public function getPassListOfAnswers(&$result_array, $active_id, $pass, $show_solutions = false, $only_answered_questions = false, $show_question_only = false, $show_reached_points = false, $anchorNav = false, ilTestQuestionRelatedObjectivesList $objectivesList = null, ilTestResultHeaderLabelBuilder $testResultHeaderLabelBuilder = null)
354    {
355        $maintemplate = new ilTemplate("tpl.il_as_tst_list_of_answers.html", true, true, "Modules/Test");
356
357        $counter = 1;
358        // output of questions with solutions
359        foreach ($result_array as $question_data) {
360            if (($question_data["workedthrough"] == 1) || ($only_answered_questions == false)) {
361                $template = new ilTemplate("tpl.il_as_qpl_question_printview.html", true, true, "Modules/TestQuestionPool");
362                $question = $question_data["qid"];
363                if (is_numeric($question)) {
364                    $maintemplate->setCurrentBlock("printview_question");
365                    $question_gui = $this->object->createQuestionGUI("", $question);
366                    if (is_object($question_gui)) {
367                        if ($this->isPdfDeliveryRequest()) {
368                            $question_gui->setRenderPurpose(assQuestionGUI::RENDER_PURPOSE_PRINT_PDF);
369                        }
370
371                        if ($anchorNav) {
372                            $template->setCurrentBlock('block_id');
373                            $template->setVariable('BLOCK_ID', "detailed_answer_block_act_{$active_id}_qst_{$question}");
374                            $template->parseCurrentBlock();
375
376                            $template->setCurrentBlock('back_anchor');
377                            $template->setVariable('HREF_BACK_ANCHOR', "#pass_details_tbl_row_act_{$active_id}_qst_{$question}");
378                            $template->setVariable('TXT_BACK_ANCHOR', $this->lng->txt('tst_back_to_question_list'));
379                            $template->parseCurrentBlock();
380                        }
381
382                        if ($show_reached_points) {
383                            $template->setCurrentBlock("result_points");
384                            $template->setVariable("RESULT_POINTS", $this->lng->txt("tst_reached_points") . ": " . $question_gui->object->getReachedPoints($active_id, $pass) . " " . $this->lng->txt("of") . " " . $question_gui->object->getMaximumPoints());
385                            $template->parseCurrentBlock();
386                        }
387                        $template->setVariable("COUNTER_QUESTION", $counter . ". ");
388                        $template->setVariable("TXT_QUESTION_ID", $this->lng->txt('question_id_short'));
389                        $template->setVariable("QUESTION_ID", $question_gui->object->getId());
390                        $template->setVariable("QUESTION_TITLE", $this->object->getQuestionTitle($question_gui->object->getTitle()));
391
392                        if ($objectivesList !== null) {
393                            $objectives = $this->lng->txt('tst_res_lo_objectives_header') . ': ';
394                            $objectives .= $objectivesList->getQuestionRelatedObjectiveTitles($question_gui->object->getId());
395                            $template->setVariable("OBJECTIVES", $objectives);
396                        }
397
398                        $show_question_only = ($this->object->getShowSolutionAnswersOnly()) ? true : false;
399
400                        $showFeedback = $this->isContextResultPresentation() && $this->object->getShowSolutionFeedback();
401                        $show_solutions = $this->isContextResultPresentation() && $show_solutions;
402
403                        if ($show_solutions) {
404                            $compare_template = new ilTemplate('tpl.il_as_tst_answers_compare.html', true, true, 'Modules/Test');
405                            $compare_template->setVariable("HEADER_PARTICIPANT", $this->lng->txt('tst_header_participant'));
406                            $compare_template->setVariable("HEADER_SOLUTION", $this->lng->txt('tst_header_solution'));
407                            $result_output = $question_gui->getSolutionOutput($active_id, $pass, $show_solutions, false, $show_question_only, $showFeedback);
408                            $best_output = $question_gui->getSolutionOutput($active_id, $pass, false, false, $show_question_only, false, true);
409
410                            $compare_template->setVariable('PARTICIPANT', $result_output);
411                            $compare_template->setVariable('SOLUTION', $best_output);
412                            if ($question_gui->supportsIntermediateSolutionOutput() && $question_gui->hasIntermediateSolution($active_id, $pass)) {
413                                $question_gui->setUseIntermediateSolution(true);
414                                $intermediate_output = $question_gui->getSolutionOutput($active_id, $pass, $show_solutions, false, true, $showFeedback);
415                                $question_gui->setUseIntermediateSolution(false);
416                                $compare_template->setVariable('TXT_INTERMEDIATE', $this->lng->txt('autosavecontent'));
417                                $compare_template->setVariable('INTERMEDIATE', $intermediate_output);
418                            }
419                            $template->setVariable('SOLUTION_OUTPUT', $compare_template->get());
420                        } else {
421                            $result_output = $question_gui->getSolutionOutput($active_id, $pass, $show_solutions, false, $show_question_only, $showFeedback);
422                            if ($question_gui->supportsIntermediateSolutionOutput() && $question_gui->hasIntermediateSolution($active_id, $pass)) {
423                                $question_gui->setUseIntermediateSolution(true);
424                                $intermediate_output = $question_gui->getSolutionOutput($active_id, $pass, $show_solutions, false, true, $showFeedback);
425                                $question_gui->setUseIntermediateSolution(false);
426                                $template->setVariable('TXT_INTERMEDIATE', $this->lng->txt('autosavecontent'));
427                                $template->setVariable('INTERMEDIATE', $intermediate_output);
428                            }
429                            $template->setVariable('SOLUTION_OUTPUT', $result_output);
430                        }
431
432                        $maintemplate->setCurrentBlock("printview_question");
433                        $maintemplate->setVariable("QUESTION_PRINTVIEW", $template->get());
434                        $maintemplate->parseCurrentBlock();
435                        $counter++;
436                    }
437                }
438            }
439        }
440
441        if ($testResultHeaderLabelBuilder !== null) {
442            if ($pass !== null) {
443                $headerText = $testResultHeaderLabelBuilder->getListOfAnswersHeaderLabel($pass + 1);
444            } else {
445                $headerText = $testResultHeaderLabelBuilder->getVirtualListOfAnswersHeaderLabel();
446            }
447        } else {
448            $headerText = '';
449        }
450
451        $maintemplate->setVariable("RESULTS_OVERVIEW", $headerText);
452        return $maintemplate->get();
453    }
454
455    /**
456     * Returns the list of answers of a users test pass and offers a scoring option
457     *
458     * @param array $result_array An array containing the results of the users test pass (generated by ilObjTest::getTestResult)
459     * @param integer $active_id Active ID of the active user
460     * @param integer $pass Test pass
461     * @param boolean $show_solutions TRUE, if the solution output should be shown in the answers, FALSE otherwise
462     * @return string HTML code of the list of answers
463     * @access public
464     *
465     * @deprecated
466     */
467    public function getPassListOfAnswersWithScoring(&$result_array, $active_id, $pass, $show_solutions = false)
468    {
469        include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
470
471        $maintemplate = new ilTemplate("tpl.il_as_tst_list_of_answers.html", true, true, "Modules/Test");
472
473        include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
474        $scoring = ilObjAssessmentFolder::_getManualScoring();
475
476        $counter = 1;
477        // output of questions with solutions
478        foreach ($result_array as $question_data) {
479            $question = $question_data["qid"];
480            if (is_numeric($question)) {
481                $question_gui = $this->object->createQuestionGUI("", $question);
482                if (in_array($question_gui->object->getQuestionTypeID(), $scoring)) {
483                    $template = new ilTemplate("tpl.il_as_qpl_question_printview.html", true, true, "Modules/TestQuestionPool");
484                    $scoretemplate = new ilTemplate("tpl.il_as_tst_manual_scoring_points.html", true, true, "Modules/Test");
485                    #mbecker: No such block. $this->tpl->setCurrentBlock("printview_question");
486                    $template->setVariable("COUNTER_QUESTION", $counter . ". ");
487                    $template->setVariable("QUESTION_TITLE", $this->object->getQuestionTitle($question_gui->object->getTitle()));
488                    $points = $question_gui->object->getMaximumPoints();
489                    if ($points == 1) {
490                        $template->setVariable("QUESTION_POINTS", $points . " " . $this->lng->txt("point"));
491                    } else {
492                        $template->setVariable("QUESTION_POINTS", $points . " " . $this->lng->txt("points"));
493                    }
494
495                    $show_question_only = ($this->object->getShowSolutionAnswersOnly()) ? true : false;
496                    $result_output = $question_gui->getSolutionOutput($active_id, $pass, $show_solutions, false, $show_question_only, $this->object->getShowSolutionFeedback(), false, true);
497
498                    $solout = $question_gui->object->getSuggestedSolutionOutput();
499                    if (strlen($solout)) {
500                        $scoretemplate->setCurrentBlock("suggested_solution");
501                        $scoretemplate->setVariable("TEXT_SUGGESTED_SOLUTION", $this->lng->txt("solution_hint"));
502                        $scoretemplate->setVariable("VALUE_SUGGESTED_SOLUTION", $solout);
503                        $scoretemplate->parseCurrentBlock();
504                    }
505
506                    $scoretemplate->setCurrentBlock("feedback");
507                    $scoretemplate->setVariable("FEEDBACK_NAME_INPUT", $question);
508                    $feedback = $this->object->getSingleManualFeedback($active_id, $question, $pass)['feedback'];
509                    $scoretemplate->setVariable("VALUE_FEEDBACK", ilUtil::prepareFormOutput($this->object->prepareTextareaOutput($feedback, true)));
510                    $scoretemplate->setVariable("TEXT_MANUAL_FEEDBACK", $this->lng->txt("set_manual_feedback"));
511                    $scoretemplate->parseCurrentBlock();
512
513                    $scoretemplate->setVariable("NAME_INPUT", $question);
514                    $this->ctrl->setParameter($this, "active_id", $active_id);
515                    $this->ctrl->setParameter($this, "pass", $pass);
516                    $scoretemplate->setVariable("FORMACTION", $this->ctrl->getFormAction($this, "manscoring"));
517                    $scoretemplate->setVariable("LABEL_INPUT", $this->lng->txt("tst_change_points_for_question"));
518                    $scoretemplate->setVariable("VALUE_INPUT", " value=\"" . assQuestion::_getReachedPoints($active_id, $question_data["qid"], $pass) . "\"");
519                    $scoretemplate->setVariable("VALUE_SAVE", $this->lng->txt("save"));
520
521                    $template->setVariable("SOLUTION_OUTPUT", $result_output);
522                    $maintemplate->setCurrentBlock("printview_question");
523                    $maintemplate->setVariable("QUESTION_PRINTVIEW", $template->get());
524                    $maintemplate->setVariable("QUESTION_SCORING", $scoretemplate->get());
525                    $maintemplate->parseCurrentBlock();
526                }
527                $counter++;
528            }
529        }
530        if ($counter == 1) {
531            // no scorable questions found
532            $maintemplate->setVariable("NO_QUESTIONS_FOUND", $this->lng->txt("manscoring_questions_not_found"));
533        }
534        $maintemplate->setVariable("RESULTS_OVERVIEW", sprintf($this->lng->txt("manscoring_results_pass"), $pass + 1));
535
536        include_once "./Services/YUI/classes/class.ilYuiUtil.php";
537        ilYuiUtil::initDomEvent();
538
539        return $maintemplate->get();
540    }
541
542    protected function getPassDetailsOverviewTableGUI($result_array, $active_id, $pass, $targetGUI, $targetCMD, $questionDetailsCMD, $questionAnchorNav, ilTestQuestionRelatedObjectivesList $objectivesList = null, $multipleObjectivesInvolved = true)
543    {
544        $this->ctrl->setParameter($targetGUI, 'active_id', $active_id);
545        $this->ctrl->setParameter($targetGUI, 'pass', $pass);
546
547        $tableGUI = $this->buildPassDetailsOverviewTableGUI($targetGUI, $targetCMD);
548
549        if (!$this->isPdfDeliveryRequest()) {
550            $tableGUI->setAnswerListAnchorEnabled($questionAnchorNav);
551        }
552
553        $tableGUI->setSingleAnswerScreenCmd($questionDetailsCMD);
554        $tableGUI->setShowHintCount($this->object->isOfferingQuestionHintsEnabled());
555
556        if ($objectivesList !== null) {
557            $tableGUI->setQuestionRelatedObjectivesList($objectivesList);
558            $tableGUI->setObjectiveOrientedPresentationEnabled(true);
559        }
560
561        $tableGUI->setMultipleObjectivesInvolved($multipleObjectivesInvolved);
562
563        $tableGUI->setActiveId($active_id);
564        $tableGUI->setShowSuggestedSolution(false);
565
566        $usersQuestionSolutions = array();
567
568        foreach ($result_array as $key => $val) {
569            if ($key === 'test' || $key === 'pass') {
570                continue;
571            }
572
573            if ($this->object->getShowSolutionSuggested() && strlen($val['solution'])) {
574                $tableGUI->setShowSuggestedSolution(true);
575            }
576
577            if (isset($val['pass'])) {
578                $tableGUI->setPassColumnEnabled(true);
579            }
580
581            $usersQuestionSolutions[$key] = $val;
582        }
583
584        $tableGUI->initColumns()->initFilter();
585
586        $tableGUI->setFilterCommand($targetCMD . 'SetTableFilter');
587        $tableGUI->setResetCommand($targetCMD . 'ResetTableFilter');
588
589        $tableGUI->setData($usersQuestionSolutions);
590
591        return $tableGUI;
592    }
593
594    /**
595     * Returns HTML code for a signature field
596     *
597     * @return string HTML code of the date and signature field for the test results
598     * @access public
599     */
600    public function getResultsSignature()
601    {
602        if ($this->object->getShowSolutionSignature() && !$this->object->getAnonymity()) {
603            $template = new ilTemplate("tpl.il_as_tst_results_userdata_signature.html", true, true, "Modules/Test");
604            $template->setVariable("TXT_DATE", $this->lng->txt("date"));
605            $old_value = ilDatePresentation::useRelativeDates();
606            ilDatePresentation::setUseRelativeDates(false);
607            $template->setVariable("VALUE_DATE", ilDatePresentation::formatDate(new ilDate(time(), IL_CAL_UNIX)));
608            ilDatePresentation::setUseRelativeDates($old_value);
609            $template->setVariable("TXT_SIGNATURE", $this->lng->txt("tst_signature"));
610            $template->setVariable("IMG_SPACER", ilUtil::getImagePath("spacer.png"));
611            return $template->get();
612        } else {
613            return "";
614        }
615    }
616
617    /**
618     * Returns the user data for a test results output
619     *
620     * @param ilTestSession|ilTestSessionDynamicQuestionSet
621     * @param integer $user_id The user ID of the user
622     * @param boolean $overwrite_anonymity TRUE if the anonymity status should be overwritten, FALSE otherwise
623     * @return string HTML code of the user data for the test results
624     * @access public
625     */
626    public function getAdditionalUsrDataHtmlAndPopulateWindowTitle($testSession, $active_id, $overwrite_anonymity = false)
627    {
628        if (!is_object($testSession)) {
629            throw new TestException();
630        }
631        $template = new ilTemplate("tpl.il_as_tst_results_userdata.html", true, true, "Modules/Test");
632        include_once './Services/User/classes/class.ilObjUser.php';
633        $user_id = $this->object->_getUserIdFromActiveId($active_id);
634        if (strlen(ilObjUser::_lookupLogin($user_id)) > 0) {
635            $user = new ilObjUser($user_id);
636        } else {
637            $user = new ilObjUser();
638            $user->setLastname($this->lng->txt("deleted_user"));
639        }
640        $t = $testSession->getSubmittedTimestamp();
641        if (!$t) {
642            $t = $this->object->_getLastAccess($testSession->getActiveId());
643        }
644
645        if ($this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired()) {
646            $uname = $this->object->userLookupFullName($user_id, $overwrite_anonymity);
647            $template->setCurrentBlock("name");
648            $template->setVariable('TXT_USR_NAME', $this->lng->txt("name"));
649            $template->setVariable('VALUE_USR_NAME', $uname);
650            $template->parseCurrentBlock();
651        }
652
653        $title_matric = "";
654        if (strlen($user->getMatriculation()) && (($this->object->getAnonymity() == false) || ($overwrite_anonymity))) {
655            $template->setCurrentBlock("matriculation");
656            $template->setVariable("TXT_USR_MATRIC", $this->lng->txt("matriculation"));
657            $template->setVariable("VALUE_USR_MATRIC", $user->getMatriculation());
658            $template->parseCurrentBlock();
659            $title_matric = " - " . $this->lng->txt("matriculation") . ": " . $user->getMatriculation();
660        }
661
662        $invited_user = array_pop($this->object->getInvitedUsers($user_id));
663        if (strlen($invited_user["clientip"])) {
664            $template->setCurrentBlock("client_ip");
665            $template->setVariable("TXT_CLIENT_IP", $this->lng->txt("client_ip"));
666            $template->setVariable("VALUE_CLIENT_IP", $invited_user["clientip"]);
667            $template->parseCurrentBlock();
668            $title_client = " - " . $this->lng->txt("clientip") . ": " . $invited_user["clientip"];
669        }
670
671        $template->setVariable("TXT_TEST_TITLE", $this->lng->txt("title"));
672        $template->setVariable("VALUE_TEST_TITLE", $this->object->getTitle());
673
674        // change the pagetitle (tab title or title in title bar of window)
675        $pagetitle = $this->object->getTitle() . $title_matric . $title_client;
676        $this->tpl->setHeaderPageTitle($pagetitle);
677
678        return $template->get();
679    }
680
681    /**
682     * Returns an output of the solution to an answer compared to the correct solution
683     *
684     * @param integer $question_id Database ID of the question
685     * @param integer $active_id Active ID of the active user
686     * @param integer $pass Test pass
687     * @return string HTML code of the correct solution comparison
688     * @access public
689     */
690    public function getCorrectSolutionOutput($question_id, $active_id, $pass, ilTestQuestionRelatedObjectivesList $objectivesList = null)
691    {
692        global $DIC;
693        $ilUser = $DIC['ilUser'];
694
695        $test_id = $this->object->getTestId();
696        $question_gui = $this->object->createQuestionGUI("", $question_id);
697
698        if ($this->isPdfDeliveryRequest()) {
699            $question_gui->setRenderPurpose(assQuestionGUI::RENDER_PURPOSE_PRINT_PDF);
700        }
701
702        $template = new ilTemplate("tpl.il_as_tst_correct_solution_output.html", true, true, "Modules/Test");
703        $show_question_only = ($this->object->getShowSolutionAnswersOnly()) ? true : false;
704        $result_output = $question_gui->getSolutionOutput($active_id, $pass, true, false, $show_question_only, $this->object->getShowSolutionFeedback(), false, false, true);
705        $best_output = $question_gui->getSolutionOutput($active_id, $pass, false, false, $show_question_only, false, true, false, false);
706        if ($this->object->getShowSolutionFeedback() && $_GET['cmd'] != 'outCorrectSolution') {
707            $specificAnswerFeedback = $question_gui->getSpecificFeedbackOutput(
708                $question_gui->object->fetchIndexedValuesFromValuePairs(
709                    $question_gui->object->getSolutionValues($active_id, $pass)
710                )
711            );
712            if (strlen($specificAnswerFeedback)) {
713                $template->setCurrentBlock("outline_specific_feedback");
714                $template->setVariable("OUTLINE_SPECIFIC_FEEDBACK", $specificAnswerFeedback);
715                $template->parseCurrentBlock();
716            }
717        }
718        if ($this->object->isBestSolutionPrintedWithResult() && strlen($best_output)) {
719            $template->setCurrentBlock("best_solution");
720            $template->setVariable("TEXT_BEST_SOLUTION", $this->lng->txt("tst_best_solution_is"));
721            $template->setVariable("BEST_OUTPUT", $best_output);
722            $template->parseCurrentBlock();
723        }
724        $template->setVariable("TEXT_YOUR_SOLUTION", $this->lng->txt("tst_your_answer_was"));
725        $template->setVariable("TEXT_SOLUTION_OUTPUT", $this->lng->txt("tst_your_answer_was")); // Mantis 28646. I don't really know why Ingmar renamed the placeholder, so
726                                                                                                // I set both old and new since the old one is set as well in several places.
727        $maxpoints = $question_gui->object->getMaximumPoints();
728        if ($maxpoints == 1) {
729            $template->setVariable("QUESTION_TITLE", $this->object->getQuestionTitle($question_gui->object->getTitle()) . " (" . $maxpoints . " " . $this->lng->txt("point") . ")");
730        } else {
731            $template->setVariable("QUESTION_TITLE", $this->object->getQuestionTitle($question_gui->object->getTitle()) . " (" . $maxpoints . " " . $this->lng->txt("points") . ")");
732        }
733        if ($objectivesList !== null) {
734            $objectives = $this->lng->txt('tst_res_lo_objectives_header') . ': ';
735            $objectives .= $objectivesList->getQuestionRelatedObjectiveTitles($question_gui->object->getId());
736            $template->setVariable('OBJECTIVES', $objectives);
737        }
738        $template->setVariable("SOLUTION_OUTPUT", $result_output);
739        $template->setVariable("RECEIVED_POINTS", sprintf($this->lng->txt("you_received_a_of_b_points"), $question_gui->object->getReachedPoints($active_id, $pass), $maxpoints));
740        $template->setVariable("FORMACTION", $this->ctrl->getFormAction($this));
741        $template->setVariable("BACKLINK_TEXT", "&lt;&lt; " . $this->lng->txt("back"));
742        return $template->get();
743    }
744
745    /**
746     * Output of the pass overview for a test called by a test participant
747     *
748     * @param ilTestSession|ilTestSessionDynamicQuestionSet $testSession
749     * @param integer $active_id
750     * @param integer $pass
751     * @param boolean $show_pass_details
752     * @param boolean $show_answers
753     * @param boolean $show_question_only
754     * @param boolean $show_reached_points
755     * @access public
756     */
757    public function getResultsOfUserOutput($testSession, $active_id, $pass, $targetGUI, $show_pass_details = true, $show_answers = true, $show_question_only = false, $show_reached_points = false)
758    {
759        global $DIC;
760        $ilObjDataCache = $DIC['ilObjDataCache'];
761
762        include_once("./Services/UICore/classes/class.ilTemplate.php");
763        $template = new ilTemplate("tpl.il_as_tst_results_participant.html", true, true, "Modules/Test");
764
765        if ($this->participantData instanceof ilTestParticipantData) {
766            $user_id = $this->participantData->getUserIdByActiveId($active_id);
767            $uname = $this->participantData->getConcatedFullnameByActiveId($active_id, false);
768        } else {
769            $user_id = $this->object->_getUserIdFromActiveId($active_id);
770            $uname = $this->object->userLookupFullName($user_id, true);
771        }
772
773        if (((array_key_exists("pass", $_GET)) && (strlen($_GET["pass"]) > 0)) || (!is_null($pass))) {
774            if (is_null($pass)) {
775                $pass = $_GET["pass"];
776            }
777        }
778
779        if (!is_null($pass)) {
780            require_once 'Modules/Test/classes/class.ilTestResultHeaderLabelBuilder.php';
781            $testResultHeaderLabelBuilder = new ilTestResultHeaderLabelBuilder($this->lng, $ilObjDataCache);
782
783            $objectivesList = null;
784
785            if ($this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired()) {
786                $testSequence = $this->testSequenceFactory->getSequenceByActiveIdAndPass($active_id, $pass);
787                $testSequence->loadFromDb();
788                $testSequence->loadQuestions();
789
790                require_once 'Modules/Course/classes/Objectives/class.ilLOTestQuestionAdapter.php';
791                $objectivesAdapter = ilLOTestQuestionAdapter::getInstance($testSession);
792
793                $objectivesList = $this->buildQuestionRelatedObjectivesList($objectivesAdapter, $testSequence);
794                $objectivesList->loadObjectivesTitles();
795
796                $testResultHeaderLabelBuilder->setObjectiveOrientedContainerId($testSession->getObjectiveOrientedContainerId());
797                $testResultHeaderLabelBuilder->setUserId($testSession->getUserId());
798                $testResultHeaderLabelBuilder->setTestObjId($this->object->getId());
799                $testResultHeaderLabelBuilder->setTestRefId($this->object->getRefId());
800                $testResultHeaderLabelBuilder->initObjectiveOrientedMode();
801            }
802
803            $result_array = $this->object->getTestResult(
804                $active_id,
805                $pass,
806                false,
807                !$this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired()
808            );
809
810            $user_id = $this->object->_getUserIdFromActiveId($active_id);
811            $showAllAnswers = true;
812            if ($this->object->isExecutable($testSession, $user_id)) {
813                $showAllAnswers = false;
814            }
815            if ($show_answers) {
816                $list_of_answers = $this->getPassListOfAnswers(
817                    $result_array,
818                    $active_id,
819                    $pass,
820                    $_SESSION['tst_results_show_best_solutions'],
821                    $showAllAnswers,
822                    $show_question_only,
823                    $show_reached_points,
824                    $show_pass_details,
825                    $objectivesList,
826                    $testResultHeaderLabelBuilder
827                );
828                $template->setVariable("LIST_OF_ANSWERS", $list_of_answers);
829            }
830
831            if ($show_pass_details) {
832                $overviewTableGUI = $this->getPassDetailsOverviewTableGUI($result_array, $active_id, $pass, $targetGUI, "getResultsOfUserOutput", '', $show_answers, $objectivesList);
833                $overviewTableGUI->setTitle($testResultHeaderLabelBuilder->getPassDetailsHeaderLabel($pass + 1));
834                $template->setVariable("PASS_DETAILS", $overviewTableGUI->getHTML());
835            }
836
837            $signature = $this->getResultsSignature();
838            $template->setVariable("SIGNATURE", $signature);
839
840            if ($this->object->isShowExamIdInTestResultsEnabled()) {
841                $template->setCurrentBlock('exam_id_footer');
842                $template->setVariable('EXAM_ID_VAL', ilObjTest::lookupExamId(
843                    $testSession->getActiveId(),
844                    $pass
845                ));
846                $template->setVariable('EXAM_ID_TXT', $this->lng->txt('exam_id'));
847                $template->parseCurrentBlock();
848            }
849        }
850
851        $template->setCurrentBlock('participant_back_anchor');
852        $template->setVariable("HREF_PARTICIPANT_BACK_ANCHOR", "#tst_results_toolbar");
853        $template->setVariable("TXT_PARTICIPANT_BACK_ANCHOR", $this->lng->txt('tst_back_to_top'));
854        $template->parseCurrentBlock();
855
856        $template->setCurrentBlock('participant_block_id');
857        $template->setVariable("PARTICIPANT_BLOCK_ID", "participant_active_{$active_id}");
858        $template->parseCurrentBlock();
859
860        if ($this->isGradingMessageRequired()) {
861            $gradingMessageBuilder = $this->getGradingMessageBuilder($active_id);
862            $gradingMessageBuilder->buildList();
863
864            $template->setCurrentBlock('grading_message');
865            $template->setVariable('GRADING_MESSAGE', $gradingMessageBuilder->getList());
866            $template->parseCurrentBlock();
867        }
868
869
870        $user_data = $this->getAdditionalUsrDataHtmlAndPopulateWindowTitle($testSession, $active_id, true);
871        $template->setVariable("TEXT_HEADING", sprintf($this->lng->txt("tst_result_user_name"), $uname));
872        $template->setVariable("USER_DATA", $user_data);
873
874        $this->populateExamId($template, (int) $active_id, (int) $pass);
875        $this->populatePassFinishDate($template, ilObjTest::lookupLastTestPassAccess($active_id, $pass));
876
877        return $template->get();
878    }
879
880    /**
881     * Returns the user and pass data for a test results output
882     *
883     * @param integer $active_id The active ID of the user
884     * @return string HTML code of the user data for the test results
885     * @access public
886     */
887    public function getResultsHeadUserAndPass($active_id, $pass)
888    {
889        $template = new ilTemplate("tpl.il_as_tst_results_head_user_pass.html", true, true, "Modules/Test");
890        include_once './Services/User/classes/class.ilObjUser.php';
891        $user_id = $this->object->_getUserIdFromActiveId($active_id);
892        if (strlen(ilObjUser::_lookupLogin($user_id)) > 0) {
893            $user = new ilObjUser($user_id);
894        } else {
895            $user = new ilObjUser();
896            $user->setLastname($this->lng->txt("deleted_user"));
897        }
898        $title_matric = "";
899        if (strlen($user->getMatriculation()) && (($this->object->getAnonymity() == false))) {
900            $template->setCurrentBlock("user_matric");
901            $template->setVariable("TXT_USR_MATRIC", $this->lng->txt("matriculation"));
902            $template->parseCurrentBlock();
903            $template->setCurrentBlock("user_matric_value");
904            $template->setVariable("VALUE_USR_MATRIC", $user->getMatriculation());
905            $template->parseCurrentBlock();
906            $template->touchBlock("user_matric_separator");
907            $title_matric = " - " . $this->lng->txt("matriculation") . ": " . $user->getMatriculation();
908        }
909
910        $invited_user = array_pop($this->object->getInvitedUsers($user_id));
911        if (strlen($invited_user["clientip"])) {
912            $template->setCurrentBlock("user_clientip");
913            $template->setVariable("TXT_CLIENT_IP", $this->lng->txt("client_ip"));
914            $template->parseCurrentBlock();
915            $template->setCurrentBlock("user_clientip_value");
916            $template->setVariable("VALUE_CLIENT_IP", $invited_user["clientip"]);
917            $template->parseCurrentBlock();
918            $template->touchBlock("user_clientip_separator");
919            $title_client = " - " . $this->lng->txt("clientip") . ": " . $invited_user["clientip"];
920        }
921
922        $template->setVariable("TXT_USR_NAME", $this->lng->txt("name"));
923        $uname = $this->object->userLookupFullName($user_id, false);
924        $template->setVariable("VALUE_USR_NAME", $uname);
925        $template->setVariable("TXT_PASS", $this->lng->txt("scored_pass"));
926        $template->setVariable("VALUE_PASS", $pass);
927        return $template->get();
928    }
929
930    /**
931     * Creates a HTML representation for the results of a given question in a test
932     *
933     * @param integer $question_id The original id of the question
934     * @param integer $test_id The test id
935     * @return string HTML code of the question results
936     */
937    public function getQuestionResultForTestUsers($question_id, $test_id)
938    {
939        // prepare generation before contents are processed (for mathjax)
940        ilPDFGeneratorUtils::prepareGenerationRequest("Test", PDF_USER_RESULT);
941
942        // REQUIRED, since we call this object regardless of the loop
943        $question_gui = $this->object->createQuestionGUI("", $question_id);
944
945        $this->object->setAccessFilteredParticipantList(
946            $this->object->buildStatisticsAccessFilteredParticipantList()
947        );
948
949        $foundusers = $this->object->getParticipantsForTestAndQuestion($test_id, $question_id);
950        $output = '';
951        foreach ($foundusers as $active_id => $passes) {
952            $resultpass = $this->object->_getResultPass($active_id);
953            for ($i = 0; $i < count($passes); $i++) {
954                if (($resultpass !== null) && ($resultpass == $passes[$i]["pass"])) {
955                    if ($output) {
956                        $output .= "<br /><br /><br />";
957                    }
958
959                    // check if re-instantiation is really neccessary
960                    $question_gui = $this->object->createQuestionGUI("", $passes[$i]["qid"]);
961                    $output .= $this->getResultsHeadUserAndPass($active_id, $resultpass + 1);
962                    $question_gui->setRenderPurpose(assQuestionGUI::RENDER_PURPOSE_PRINT_PDF);
963                    $output .= $question_gui->getSolutionOutput(
964                        $active_id,
965                        $resultpass,
966                        $graphicalOutput = false,
967                        $result_output = false,
968                        $show_question_only = false,
969                        $show_feedback = false
970                    );
971                }
972            }
973        }
974
975        require_once './Modules/Test/classes/class.ilTestPDFGenerator.php';
976        ilTestPDFGenerator::generatePDF($output, ilTestPDFGenerator::PDF_OUTPUT_DOWNLOAD, $question_gui->object->getTitleFilenameCompliant(), PDF_USER_RESULT);
977    }
978
979    /**
980     * @return ilTestPassDetailsOverviewTableGUI
981     */
982    protected function buildPassDetailsOverviewTableGUI($targetGUI, $targetCMD)
983    {
984        if (!isset($targetGUI->object) && method_exists($targetGUI, 'getTestObj')) {
985            $targetGUI->object = $targetGUI->getTestObj();
986        }
987
988        require_once 'Modules/Test/classes/tables/class.ilTestPassDetailsOverviewTableGUI.php';
989        $tableGUI = new ilTestPassDetailsOverviewTableGUI($this->ctrl, $targetGUI, $targetCMD);
990        $tableGUI->setIsPdfGenerationRequest($this->isPdfDeliveryRequest());
991        return $tableGUI;
992    }
993
994    protected function isGradingMessageRequired()
995    {
996        if ($this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired()) {
997            return false;
998        }
999
1000        if ($this->object->isShowGradingStatusEnabled()) {
1001            return true;
1002        }
1003
1004        if ($this->object->isShowGradingMarkEnabled()) {
1005            return true;
1006        }
1007
1008        if ($this->object->areObligationsEnabled()) {
1009            return true;
1010        }
1011
1012        return false;
1013    }
1014
1015    /**
1016     * @param integer $activeId
1017     * @return ilTestGradingMessageBuilder
1018     */
1019    protected function getGradingMessageBuilder($activeId)
1020    {
1021        require_once 'Modules/Test/classes/class.ilTestGradingMessageBuilder.php';
1022        $gradingMessageBuilder = new ilTestGradingMessageBuilder($this->lng, $this->object);
1023
1024        $gradingMessageBuilder->setActiveId($activeId);
1025
1026        return $gradingMessageBuilder;
1027    }
1028
1029    protected function buildQuestionRelatedObjectivesList(ilLOTestQuestionAdapter $objectivesAdapter, ilTestQuestionSequence $testSequence)
1030    {
1031        require_once 'Modules/Test/classes/class.ilTestQuestionRelatedObjectivesList.php';
1032        $questionRelatedObjectivesList = new ilTestQuestionRelatedObjectivesList();
1033
1034        $objectivesAdapter->buildQuestionRelatedObjectiveList($testSequence, $questionRelatedObjectivesList);
1035
1036        return $questionRelatedObjectivesList;
1037    }
1038
1039    protected function getFilteredTestResult($active_id, $pass, $considerHiddenQuestions, $considerOptionalQuestions)
1040    {
1041        global $DIC;
1042        $ilDB = $DIC['ilDB'];
1043        $ilPluginAdmin = $DIC['ilPluginAdmin'];
1044
1045        $table_gui = $this->buildPassDetailsOverviewTableGUI($this, 'outUserPassDetails');
1046        $table_gui->initFilter();
1047
1048        require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionList.php';
1049        $questionList = new ilAssQuestionList($ilDB, $this->lng, $ilPluginAdmin);
1050
1051        $questionList->setParentObjIdsFilter(array($this->object->getId()));
1052        $questionList->setQuestionInstanceTypeFilter(ilAssQuestionList::QUESTION_INSTANCE_TYPE_DUPLICATES);
1053
1054        foreach ($table_gui->getFilterItems() as $item) {
1055            if (substr($item->getPostVar(), 0, strlen('tax_')) == 'tax_') {
1056                $v = $item->getValue();
1057
1058                if (is_array($v) && count($v) && !(int) $v[0]) {
1059                    continue;
1060                }
1061
1062                $taxId = substr($item->getPostVar(), strlen('tax_'));
1063                $questionList->addTaxonomyFilter($taxId, $item->getValue(), $this->object->getId(), 'tst');
1064            } elseif ($item->getValue() !== false) {
1065                $questionList->addFieldFilter($item->getPostVar(), $item->getValue());
1066            }
1067        }
1068
1069        $questionList->load();
1070
1071        $filteredTestResult = array();
1072
1073        $resultData = $this->object->getTestResult($active_id, $pass, false, $considerHiddenQuestions, $considerOptionalQuestions);
1074
1075        foreach ($resultData as $resultItemKey => $resultItemValue) {
1076            if ($resultItemKey === 'test' || $resultItemKey === 'pass') {
1077                continue;
1078            }
1079
1080            if (!$questionList->isInList($resultItemValue['qid'])) {
1081                continue;
1082            }
1083
1084            $filteredTestResult[] = $resultItemValue;
1085        }
1086
1087        return $filteredTestResult;
1088    }
1089
1090    /**
1091     * @param string $content
1092     */
1093    protected function populateContent($content)
1094    {
1095        if ($this->isPdfDeliveryRequest()) {
1096            ilTestPDFGenerator::generatePDF(
1097                $content,
1098                ilTestPDFGenerator::PDF_OUTPUT_DOWNLOAD,
1099                $this->object->getTitleFilenameCompliant(),
1100                PDF_USER_RESULT
1101            );
1102        } else {
1103            $this->tpl->setContent($content);
1104        }
1105    }
1106
1107    /**
1108     * @return ilTestResultsToolbarGUI
1109     */
1110    protected function buildUserTestResultsToolbarGUI()
1111    {
1112        require_once 'Modules/Test/classes/toolbars/class.ilTestResultsToolbarGUI.php';
1113        $toolbar = new ilTestResultsToolbarGUI($this->ctrl, $this->tpl, $this->lng);
1114
1115        return $toolbar;
1116    }
1117
1118    protected function outCorrectSolutionCmd()
1119    {
1120        $this->outCorrectSolution(); // cannot be named xxxCmd, because it's also called from context without Cmd in names
1121    }
1122
1123    /**
1124     * Creates an output of the solution of an answer compared to the correct solution
1125     *
1126     * @access public
1127     */
1128    protected function outCorrectSolution()
1129    {
1130        if (!$this->object->getShowSolutionDetails()) {
1131            ilUtil::sendInfo($this->lng->txt("no_permission"), true);
1132            $this->ctrl->redirectByClass("ilobjtestgui", "infoScreen");
1133        }
1134
1135        $testSession = $this->testSessionFactory->getSession();
1136        $activeId = $testSession->getActiveId();
1137
1138        if (!($activeId > 0)) {
1139            $this->ctrl->redirectByClass("ilobjtestgui", "infoScreen");
1140        }
1141
1142        $this->ctrl->saveParameter($this, "pass");
1143        $pass = (int) $_GET['pass'];
1144
1145        $questionId = (int) $_GET['evaluation'];
1146
1147        $testSequence = $this->testSequenceFactory->getSequenceByActiveIdAndPass($activeId, $pass);
1148        $testSequence->loadFromDb();
1149        $testSequence->loadQuestions();
1150
1151        if (!$testSequence->questionExists($questionId)) {
1152            ilObjTestGUI::accessViolationRedirect();
1153        }
1154
1155        if ($this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired()) {
1156            $testSequence = $this->testSequenceFactory->getSequenceByActiveIdAndPass($activeId, $pass);
1157            $testSequence->loadFromDb();
1158            $testSequence->loadQuestions();
1159
1160            require_once 'Modules/Course/classes/Objectives/class.ilLOTestQuestionAdapter.php';
1161            $objectivesAdapter = ilLOTestQuestionAdapter::getInstance($testSession);
1162            $objectivesList = $this->buildQuestionRelatedObjectivesList($objectivesAdapter, $testSequence);
1163            $objectivesList->loadObjectivesTitles();
1164        } else {
1165            $objectivesList = null;
1166        }
1167
1168        global $DIC;
1169        $ilTabs = $DIC['ilTabs'];
1170
1171        if ($this instanceof ilTestEvalObjectiveOrientedGUI) {
1172            $ilTabs->setBackTarget(
1173                $this->lng->txt("tst_back_to_virtual_pass"),
1174                $this->ctrl->getLinkTarget($this, 'showVirtualPass')
1175            );
1176        } else {
1177            $ilTabs->setBackTarget(
1178                $this->lng->txt("tst_back_to_pass_details"),
1179                $this->ctrl->getLinkTarget($this, 'outUserPassDetails')
1180            );
1181        }
1182        $ilTabs->clearSubTabs();
1183
1184        include_once("./Services/Style/Content/classes/class.ilObjStyleSheet.php");
1185        $this->tpl->setCurrentBlock("ContentStyle");
1186        $this->tpl->setVariable("LOCATION_CONTENT_STYLESHEET", ilObjStyleSheet::getContentStylePath(0));
1187        $this->tpl->parseCurrentBlock();
1188
1189        $this->tpl->setCurrentBlock("SyntaxStyle");
1190        $this->tpl->setVariable("LOCATION_SYNTAX_STYLESHEET", ilObjStyleSheet::getSyntaxStylePath());
1191        $this->tpl->parseCurrentBlock();
1192
1193        $this->tpl->addCss(ilUtil::getStyleSheetLocation("output", "test_print.css", "Modules/Test"), "print");
1194        if ($this->object->getShowSolutionAnswersOnly()) {
1195            $this->tpl->addCss(ilUtil::getStyleSheetLocation("output", "test_print_hide_content.css", "Modules/Test"), "print");
1196        }
1197
1198        $solution = $this->getCorrectSolutionOutput($questionId, $activeId, $pass, $objectivesList);
1199
1200        $this->tpl->setContent($solution);
1201    }
1202
1203    /**
1204     * @param ilTemplate $tpl
1205     * @param int $passFinishDate
1206     */
1207    public function populatePassFinishDate($tpl, $passFinishDate)
1208    {
1209        $oldValue = ilDatePresentation::useRelativeDates();
1210        ilDatePresentation::setUseRelativeDates(false);
1211        $passFinishDate = ilDatePresentation::formatDate(new ilDateTime($passFinishDate, IL_CAL_UNIX));
1212        ilDatePresentation::setUseRelativeDates($oldValue);
1213        $tpl->setVariable("PASS_FINISH_DATE_LABEL", $this->lng->txt('tst_pass_finished_on'));
1214        $tpl->setVariable("PASS_FINISH_DATE_VALUE", $passFinishDate);
1215    }
1216
1217    /**
1218     * @param ilTemplate $tpl
1219     * @param int $activeId
1220     * @param int $pass
1221     */
1222    public function populateExamId(ilTemplate $tpl, int $activeId, int $pass)
1223    {
1224        if ($this->object->isShowExamIdInTestResultsEnabled()) {
1225            $tpl->setVariable("EXAM_ID_TXT", $this->lng->txt('exam_id'));
1226            $tpl->setVariable('EXAM_ID', ilObjTest::lookupExamId(
1227                $activeId,
1228                $pass
1229            ));
1230        }
1231    }
1232}
1233
1234// internal sort function to sort the result array
1235function sortResults($a, $b)
1236{
1237    $sort = ($_GET["sort"]) ? ($_GET["sort"]) : "nr";
1238    $sortorder = ($_GET["sortorder"]) ? ($_GET["sortorder"]) : "asc";
1239    if (strcmp($sortorder, "asc")) {
1240        $smaller = 1;
1241        $greater = -1;
1242    } else {
1243        $smaller = -1;
1244        $greater = 1;
1245    }
1246    if ($a[$sort] == $b[$sort]) {
1247        return 0;
1248    }
1249    return ($a[$sort] < $b[$sort]) ? $smaller : $greater;
1250}
1251