ILIAS  trunk Revision v12.0_alpha-377-g3641b37b9db
class.ilTestEvaluationGUI.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
21use ILIAS\Test\Results\Presentation\TitlesBuilder as ResultsTitlesBuilder;
23use ILIAS\UI\Component\ViewControl\Mode as ViewControlMode;
24use ILIAS\UI\Component\Link\Standard as StandardLink;
25use ILIAS\UI\Component\Panel\Sub as SubPanel;
27
47{
48 private const DEFAULT_CMD = 'outUserListOfAnswerPasses';
51
52 public function __construct(ilObjTest $object)
53 {
54 parent::__construct($object);
55 $this->participant_access_filter = new ilTestParticipantAccessFilterFactory($this->access);
56
57 $this->processLockerFactory = new ilTestProcessLockerFactory(
58 new ilSetting('assessment'),
59 $this->db,
60 $this->object->getTestLogger()
61 );
62 }
63
64 public function getTestAccess(): ilTestAccess
65 {
66 return $this->testAccess;
67 }
68
69 public function setTestAccess($testAccess): void
70 {
71 $this->testAccess = $testAccess;
72 }
73
74 public function executeCommand()
75 {
76 $cmd = $this->ctrl->getCmd(self::DEFAULT_CMD);
77 $next_class = $this->ctrl->getNextClass($this);
78 $this->ctrl->saveParameter($this, 'sequence');
79 $this->ctrl->saveParameter($this, 'active_id');
80
81 switch ($next_class) {
82 case 'iltestpassdetailsoverviewtablegui':
83 $tableGUI = new ilTestPassDetailsOverviewTableGUI($this->ctrl, $this, 'outUserPassDetails');
84 $this->ctrl->forwardCommand($tableGUI);
85 break;
86
87 default:
88 if (in_array($cmd, ['excel_scored_test_run', 'excel_all_test_runs'])) {
89 $ret = $this->exportEvaluation($cmd);
90 } elseif (in_array($cmd, ['excel_all_test_runs_a'])) {
91 $ret = $this->exportAggregatedResults($cmd);
92 } else {
93 $ret = $this->$cmd();
94 }
95 break;
96 }
97 return $ret;
98 }
99
106 public function getEvaluationQuestionId($question_id, $original_id = '')
107 {
108 if ($original_id > 0) {
109 return $original_id;
110 } else {
111 return $question_id;
112 }
113 }
114
115 protected function setCss(): void
116 {
117 $this->tpl->addCss(ilUtil::getStyleSheetLocation('output', 'test_print.css'), 'print');
118 if ($this->object->getShowSolutionAnswersOnly()) {
119 $this->tpl->addCss(ilUtil::getStyleSheetLocation('output', 'test_print_hide_content.css'), 'print');
120 }
121 $this->tpl->addCss(ilObjStyleSheet::getContentStylePath(0));
122 }
123
124 public function printResults(): void
125 {
126 $this->ctrl->saveParameterByClass(self::class, 'active_ids');
127 $this->global_screen->tool()->context()->current()->addAdditionalData(
128 PrintLayoutProvider::TEST_CONTEXT_PRINT,
129 true
130 );
131
132 $selected_active_ids = explode(',', $this->testrequest->strVal('active_ids'));
133 $results_panel = $this->ui_factory->panel()->report(
134 $this->lng->txt('tst_results'),
135 array_map(
136 function (string $v): SubPanel {
137 $value = (int) $v;
138 $attempt_id = ilObjTest::_getResultPass($value);
139 $components = $this->buildAttemptComponents($value, $attempt_id, false, true);
140 return $this->ui_factory->panel()->sub(
141 $this->buildResultsTitle(
142 ilObjUser::_lookupFullname($this->object->_getUserIdFromActiveId($value)),
143 $attempt_id
144 ),
146 );
147 },
148 $selected_active_ids
149 )
150 );
151
152 $this->tpl->setVariable(
153 'ADM_CONTENT',
154 $this->ui_renderer->render([
155 $results_panel,
156 $this->ui_factory->legacy()->content('')->withAdditionalOnLoadCode(
157 fn(string $id): string => 'setTimeout(() => {window.print();}, 50)'
158 )
159 ])
160 );
161 }
162
163 public function showResults(): void
164 {
165 $this->setCss();
166 $this->ctrl->saveParameterByClass(self::class, 'active_ids');
167 $selected_active_ids = explode(',', $this->testrequest->strVal('active_ids'));
168
171
172 $current_active_id = (int) $selected_active_ids[0];
173 if (count($selected_active_ids) > 1
174 && ($selected_active_id = $this->testrequest->getActiveId()) > 0
175 && array_search($selected_active_id, $selected_active_ids) !== false) {
176 $current_active_id = $selected_active_id;
177 }
178
179 if ($this->testrequest->isset('attempt')) {
180 $attempt_id = $this->testrequest->int('attempt');
181 } else {
182 $attempt_id = ilObjTest::_getResultPass($current_active_id);
183 }
184
185 $results_panel = $this->ui_factory->panel()->report(
186 $this->buildResultsTitle(
187 ilObjUser::_lookupFullname($this->object->_getUserIdFromActiveId($current_active_id)),
188 $attempt_id
189 ),
190 $this->buildAttemptComponents($current_active_id, $attempt_id, true, false)
191 );
192
193 $attempts_ids_array = $this->results_data_factory->getAttemptIdsArrayFor(
194 $this->object,
195 $current_active_id
196 );
197
198 if (count($attempts_ids_array) > 1) {
199 $results_panel = $results_panel->withViewControls([
201 $attempts_ids_array,
202 ++$attempt_id
203 )
204 ]);
205 }
206
207 if (count($selected_active_ids) > 1) {
208 $this->addParticipantSelectorToToolbar($selected_active_ids, $current_active_id);
209 }
210
211 $this->tpl->setVariable(
212 'ADM_CONTENT',
213 $this->ui_renderer->render($results_panel)
214 );
215
216 $this->tabs->setBackTarget(
217 $this->lng->txt('back'),
218 $this->ctrl->getLinkTargetByClass(['ilTestParticipantsGUI'])
219 );
220 }
221
222 public function outUserPassDetails(): void
223 {
224 $this->tabs->clearSubTabs();
225 $this->tabs->setBackTarget($this->lng->txt('tst_results_back_overview'), $this->ctrl->getLinkTarget($this));
226
227 $test_session = $this->test_session_factory->getSession();
228
229 if (!$this->object->getShowPassDetails()) {
230 $this->ctrl->redirectByClass([ilRepositoryGUI::class, ilObjTestGUI::class, ilInfoScreenGUI::class]);
231 }
232
233 $active_id = $test_session->getActiveId();
234 $user_id = $test_session->getUserId();
235
236 $this->ctrl->saveParameter($this, 'pass');
237 $pass = $this->testrequest->int('pass');
238
239 $test_result_header_label_builder = new ResultsTitlesBuilder($this->lng, $this->obj_cache);
240
241 $objectives_list = null;
242
243 $consider_hidden_questions = true;
244 $consider_optional_questions = true;
245
246 if ($this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired()) {
247 $consider_hidden_questions = false;
248 $consider_optional_questions = true;
249
250 $test_sequence = $this->test_sequence_factory->getSequenceByActiveIdAndPass($active_id, $pass);
251 $test_sequence->loadFromDb();
252 $test_sequence->loadQuestions();
253
254 if ($this->object->isRandomTest() && !$test_sequence->isAnsweringOptionalQuestionsConfirmed()) {
255 $consider_optional_questions = false;
256 }
257
258 $objectivesAdapter = ilLOTestQuestionAdapter::getInstance($test_session);
259
260 $objectives_list = $this->buildQuestionRelatedObjectivesList($objectivesAdapter, $test_sequence);
261 $objectives_list->loadObjectivesTitles();
262
263 $test_result_header_label_builder->setObjectiveOrientedContainerId($test_session->getObjectiveOrientedContainerId());
264 $test_result_header_label_builder->setUserId($test_session->getUserId());
265 $test_result_header_label_builder->setTestObjId($this->object->getId());
266 $test_result_header_label_builder->setTestRefId($this->object->getRefId());
267 $test_result_header_label_builder->initObjectiveOrientedMode();
268 }
269
270 $tpl = new ilTemplate('tpl.il_as_tst_pass_details_overview_participants.html', true, true, 'components/ILIAS/Test');
271
273
274 if ((new ilCertificateDownloadValidator())->isCertificateDownloadable($user_id, $this->object->getId())) {
276 }
277
278 $tpl->setCurrentBlock('signature');
279 $tpl->setVariable('SIGNATURE', $this->getResultsSignature());
281
282 if ($this->object->isShowExamIdInTestResultsEnabled()) {
283 if ($this->object->isShowExamIdInTestResultsEnabled()) {
285 $test_session->getActiveId(),
286 $pass
287 ));
288 $tpl->setVariable('EXAM_ID_TXT', $this->lng->txt('exam_id'));
289 }
290 }
291
292 if (!$this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired() &&
293 $this->isGradingMessageRequired() && $this->object->getNrOfTries() == 1) {
294 $grading_message_builder = $this->getGradingMessageBuilder($active_id);
295 $grading_message_builder->buildMessage();
296 $grading_message_builder->sendMessage();
297 }
298
299 $data = $this->object->getCompleteEvaluationData();
300 $reached = $data->getParticipant($active_id)->getPass($pass)->getReachedPoints();
301 $max = $data->getParticipant($active_id)->getPass($pass)->getMaxPoints();
302 $percent = $max ? $reached / $max * 100.0 : 0;
303 $result = $data->getParticipant($active_id)->getPass($pass)->getReachedPoints() . ' ' . strtolower($this->lng->txt('of')) . ' ' . $data->getParticipant($active_id)->getPass($pass)->getMaxPoints() . ' (' . sprintf('%2.2f', $percent) . ' %' . ')';
304 $tpl->setCurrentBlock('total_score');
305 $tpl->setVariable('TOTAL_RESULT_TEXT', $this->lng->txt('tst_stat_result_resultspoints'));
306 $tpl->setVariable('TOTAL_RESULT', $result);
308
309 $tpl->setVariable('TEXT_RESULTS', $test_result_header_label_builder->getPassDetailsHeaderLabel($pass + 1));
310 $tpl->setVariable('FORMACTION', $this->ctrl->getFormAction($this));
311
312 $this->populateExamId($tpl, $active_id, (int) $pass);
313 $this->populatePassFinishDate($tpl, ilObjTest::lookupLastTestPassAccess($active_id, $pass));
314
315 $this->setCss();
316
317 $settings = $this->results_presentation_factory->getAttemptResultsSettings(
318 $this->object,
319 true
320 );
321 $table = $this->results_presentation_factory->getAttemptResultsPresentationTable(
322 $this->results_data_factory->getAttemptResultsFor(
323 $settings,
324 $this->object,
325 $active_id,
326 $pass,
327 true
328 ),
329 $settings,
330 $this->buildResultsTitle($this->user->getFullname(), $pass),
331 false
332 );
333
334 $tpl->setVariable('LIST_OF_ANSWERS', $table->render());
335
336 $this->tpl->addCss(ilObjStyleSheet::getContentStylePath(0));
337
338 $this->tpl->setContent(
339 $tpl->get()
340 );
341 }
342
343 public function outUserResultsOverview()
344 {
345 $test_session = $this->test_session_factory->getSession();
346 $active_id = $test_session->getActiveId();
347 $user_id = $this->user->getId();
348 $uname = $this->object->userLookupFullName($user_id, true);
349
350 if (!$this->object->canShowTestResults($test_session)) {
351 $this->ctrl->redirectByClass([ilRepositoryGUI::class, ilObjTestGUI::class, ilInfoScreenGUI::class]);
352 }
353
354 $templatehead = new ilTemplate('tpl.il_as_tst_results_participants.html', true, true, 'components/ILIAS/Test');
355 $template = new ilTemplate('tpl.il_as_tst_results_participant.html', true, true, 'components/ILIAS/Test');
356
358
359 if ((new ilCertificateDownloadValidator())->isCertificateDownloadable($user_id, $this->object->getId())) {
361 }
362
363 $test_result_header_label_builder = new ResultsTitlesBuilder($this->lng, $this->obj_cache);
364 if ($this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired()) {
365 $test_result_header_label_builder->setObjectiveOrientedContainerId($test_session->getObjectiveOrientedContainerId());
366 $test_result_header_label_builder->setUserId($test_session->getUserId());
367 $test_result_header_label_builder->setTestObjId($this->object->getId());
368 $test_result_header_label_builder->setTestRefId($this->object->getRefId());
369 $test_result_header_label_builder->initObjectiveOrientedMode();
370 }
371
372 $template->setCurrentBlock('pass_overview');
373
374 $test_passes_selector = new ilTestPassesSelector($this->db, $this->object);
375 $test_passes_selector->setActiveId($test_session->getActiveId());
376 $test_passes_selector->setLastFinishedPass($test_session->getLastFinishedPass());
377
378 $pass_overview_table_gui = $this->buildPassOverviewTableGUI($this);
379 $pass_overview_table_gui->setActiveId($test_session->getActiveId());
380 $pass_overview_table_gui->setResultPresentationEnabled(true);
381 if ($this->object->getShowPassDetails()) {
382 $pass_overview_table_gui->setPassDetailsCommand('outUserPassDetails');
383 }
384 if ($this->object->isPassDeletionAllowed()) {
385 $pass_overview_table_gui->setPassDeletionCommand('confirmDeletePass');
386 }
387 $pass_overview_table_gui->init();
388 $pass_overview_table_gui->setData($this->getPassOverviewTableData($test_session, $test_passes_selector->getReportablePasses(), true));
389 $pass_overview_table_gui->setTitle($test_result_header_label_builder->getPassOverviewHeaderLabel());
390 $overview = $pass_overview_table_gui->getHTML();
391 if ($this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired()) {
392 $lo_status = new ilTestLearningObjectivesStatusGUI(
393 $this->lng,
394 $this->ctrl,
395 $this->ui_factory,
396 $this->ui_renderer,
397 $this->testrequest
398 );
399 $lo_status->setCrsObjId($this->getObjectiveOrientedContainer()->getObjId());
400 $lo_status->setUsrId($test_session->getUserId());
401 $overview .= '<br />' . $lo_status->getHTML();
402 }
403 $template->setVariable('PASS_OVERVIEW', $overview);
404 $template->parseCurrentBlock();
405
406 if ($this->isGradingMessageRequired()) {
407 $grading_message_builder = $this->getGradingMessageBuilder($active_id);
408 $grading_message_builder->buildMessage();
409 $grading_message_builder->sendMessage();
410 }
411
412 $user_data = $this->getAdditionalUsrDataHtmlAndPopulateWindowTitle($test_session, $active_id, true);
413
414 if (!$this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired()) {
415 if ($this->object->getAnonymity()) {
416 $template->setVariable('TEXT_HEADING', $this->lng->txt('tst_result'));
417 } else {
418 $template->setVariable('TEXT_HEADING', sprintf($this->lng->txt('tst_result_user_name'), $uname));
419 $template->setVariable('USER_DATA', $user_data);
420 }
421 }
422
423 $this->setCss();
424 $templatehead->setVariable('RESULTS_PARTICIPANT', $template->get());
425 $this->tpl->setContent($templatehead->get());
426 }
427
429 {
430 if (!$this->object->getShowSolutionPrintview()) {
431 $this->tpl->setOnScreenMessage('info', $this->lng->txt('no_permission'), true);
432 $this->ctrl->redirectByClass([ilRepositoryGUI::class, ilObjTestGUI::class, ilInfoScreenGUI::class]);
433 }
434
435 $template = new ilTemplate('tpl.il_as_tst_info_list_of_answers.html', true, true, 'components/ILIAS/Test');
436
437 $user_id = $this->user->getId();
438
439 $test_session = $this->test_session_factory->getSession();
440 $active_id = $test_session->getActiveId();
441
442 if ($this->testrequest->isset('attempt')) {
443 $attempt = $this->testrequest->int('attempt');
444 } else {
445 $attempt = \ilObjTest::_getResultPass($test_session->getActiveId());
446 }
447
448 $test_passes_selector = new ilTestPassesSelector($this->db, $this->object);
449 $test_passes_selector->setActiveId($test_session->getActiveId());
450 $test_passes_selector->setLastFinishedPass($test_session->getLastFinishedPass());
451
452 if (count($test_passes_selector->getClosedPasses()) > 1) {
453 $this->addAttemptSwitchingViewControlToToolbar($test_passes_selector->getClosedPasses(), $attempt);
454 }
455
457
458 $test_result_header_label_builder = new ResultsTitlesBuilder($this->lng, $this->obj_cache);
459 $test_result_header_label_builder->setAttemptLastAccessDate(
460 (new \DateTimeImmutable(
461 '@' . ilObjTest::lookupLastTestPassAccess($test_session->getActiveId(), $attempt)
462 ))->setTimezone(new \DateTimeZone($this->user->getTimeZone()))
463 ->format($this->user->getDateTimeFormat()->toString())
464 );
465
466 $objectives_list = null;
467 if ($this->getObjectiveOrientedContainer()?->isObjectiveOrientedPresentationRequired()) {
468 $test_sequence = $this->test_sequence_factory->getSequenceByActiveIdAndPass($active_id, $attempt);
469 $test_sequence->loadFromDb();
470 $test_sequence->loadQuestions();
471
472 $objectivesAdapter = ilLOTestQuestionAdapter::getInstance($test_session);
473
474 $objectives_list = $this->buildQuestionRelatedObjectivesList($objectivesAdapter, $test_sequence);
475 $objectives_list->loadObjectivesTitles();
476
477 $test_result_header_label_builder->setObjectiveOrientedContainerId($test_session->getObjectiveOrientedContainerId());
478 $test_result_header_label_builder->setUserId($test_session->getUserId());
479 $test_result_header_label_builder->setTestObjId($this->object->getId());
480 $test_result_header_label_builder->setTestRefId($this->object->getRefId());
481 $test_result_header_label_builder->initObjectiveOrientedMode();
482 }
483
484 $result_array = $this->object->getTestResult(
485 $active_id,
486 $attempt,
487 false,
488 !$this->getObjectiveOrientedContainer()?->isObjectiveOrientedPresentationRequired()
489 );
490
491 $signature = $this->getResultsSignature();
492 $show_all_answers = true;
493 if ($this->object->isExecutable($test_session, $user_id)) {
494 $show_all_answers = false;
495 }
496 $this->setContextResultPresentation(false);
497 $answers = $this->getPassListOfAnswers(
498 $result_array,
499 $active_id,
500 $attempt,
501 false,
502 $show_all_answers,
503 false,
504 false,
505 false,
506 $objectives_list,
507 $test_result_header_label_builder
508 );
509 $template->setVariable('PASS_DETAILS', $answers);
510
511 $user_data = $this->getAdditionalUsrDataHtmlAndPopulateWindowTitle($test_session, $active_id, true);
512 $template->setVariable('USER_DATA', $user_data);
513 if (strlen($signature)) {
514 $template->setVariable('SIGNATURE', $signature);
515 }
516 if (!is_null($attempt) && $this->object->isShowExamIdInTestResultsEnabled()) {
517 $template->setCurrentBlock('exam_id_footer');
518 $template->setVariable('EXAM_ID_VAL', ilObjTest::lookupExamId(
519 $test_session->getActiveId(),
520 $attempt
521 ));
522 $template->setVariable('EXAM_ID_TXT', $this->lng->txt('exam_id'));
523 $template->parseCurrentBlock();
524 }
525
526 $this->setCss();
527 $this->tpl->setVariable('ADM_CONTENT', $template->get());
528 }
529
530 public function outCertificate()
531 {
532 $ilUserCertificateRepository = new ilUserCertificateRepository($this->db, $this->logger->getComponentLogger());
533 $pdfGenerator = new ilPdfGenerator($ilUserCertificateRepository);
534
535 $pdfAction = new ilCertificatePdfAction(
536 $pdfGenerator,
538 $this->lng->txt('error_creating_certificate_pdf')
539 );
540
541 $pdfAction->downloadPdf($this->user->getId(), $this->object->getId());
542 }
543
544 public function confirmDeletePass()
545 {
546 if ($this->testrequest->isset('context') && strlen($this->testrequest->raw('context'))) {
547 $context = $this->testrequest->raw('context');
548 } else {
550 }
551
552 if (!$this->object->isPassDeletionAllowed()) {
554 }
555
556 $confirm = new ilTestPassDeletionConfirmationGUI($this->ctrl, $this->lng, $this);
557 $confirm->build($this->testrequest->getActiveId('active_id'), $this->testrequest->int('pass'), $context);
558
559 $this->tpl->setContent($this->ctrl->getHTML($confirm));
560 }
561
562 public function cancelDeletePass(): void
563 {
564 $this->redirectToPassDeletionContext($this->testrequest->strVal('context'));
565 }
566
567 private function redirectToPassDeletionContext(string $context): void
568 {
569 switch ($context) {
571
572 $this->ctrl->redirect($this, 'outUserResultsOverview');
573
574 // no break
576 $this->ctrl->redirectByClass([ilRepositoryGUI::class, ilObjTestGUI::class, ilInfoScreenGUI::class]);
577 }
578 }
579
580 public function performDeletePass(): void
581 {
582 $context = $this->testrequest->strVal('context') ?? ilTestPassDeletionConfirmationGUI::CONTEXT_PASS_OVERVIEW;
583 $active_fi = $this->testrequest->int('active_id');
584 $pass = $this->testrequest->int('pass');
585
586 if (!$this->object->isPassDeletionAllowed()) {
588 }
589
591
592 if ($active_fi === 0 || !$this->testrequest->isset('pass')) {
593 $this->ctrl->redirect($this, 'outUserResultsOverview');
594 }
595
596 if ($pass === ilObjTest::_getResultPass($active_fi)) {
597 $this->ctrl->redirect($this, 'outUserResultsOverview');
598 }
599
600 // Get information
601 $result = $ilDB->query("
602 SELECT tst_active.tries, tst_active.last_finished_pass, tst_sequence.pass
603 FROM tst_active
604 LEFT JOIN tst_sequence
605 ON tst_sequence.active_fi = tst_active.active_id
606 AND tst_sequence.pass = tst_active.tries
607 WHERE tst_active.active_id = {$ilDB->quote($active_fi, 'integer')}
608 ");
609
610 $row = $ilDB->fetchAssoc($result);
611
612 $tries = $row['tries'];
613 $lastFinishedPass = is_numeric($row['last_finished_pass']) ? $row['last_finished_pass'] : -1;
614
615 if ($pass < $lastFinishedPass) {
616 $isActivePass = false;
617 $must_renumber = true;
618 } elseif ($pass == $lastFinishedPass) {
619 $isActivePass = false;
620
621 if ($tries == $row['pass']) {
622 $must_renumber = true;
623 } else {
624 $must_renumber = false;
625 }
626 } elseif ($pass == $row['pass']) {
627 $isActivePass = true;
628 $must_renumber = false;
629 } else {
630 throw new ilTestException('This should not happen, please contact Bjoern Heyser to clean up this pass salad!');
631 }
632
633 if ($isActivePass) {
634 $this->ctrl->redirect($this, 'outUserResultsOverview');
635 }
636
637 if ($pass == 0 && (
638 ($lastFinishedPass == 0 && $tries == 1 && $tries != $row['pass'])
639 || ($isActivePass == true) // should be equal to || ($lastFinishedPass == -1 && $tries == 0)
640 )) {
641 $last_pass = true;
642 } else {
643 $last_pass = false;
644 }
645
646 // Work on tables:
647 // tst_active
648 if ($last_pass) {
649 $ilDB->manipulate(
650 'DELETE
651 FROM tst_active
652 WHERE active_id = ' . $ilDB->quote($active_fi, 'integer')
653 );
654 } elseif (!$isActivePass) {
655 $ilDB->manipulate(
656 'UPDATE tst_active
657 SET tries = ' . $ilDB->quote($tries - 1, 'integer') . ',
658 last_finished_pass = ' . $ilDB->quote($lastFinishedPass - 1, 'integer') . '
659 WHERE active_id = ' . $ilDB->quote($active_fi, 'integer')
660 );
661 }
662 // tst_manual_fb
663 $ilDB->manipulate(
664 'DELETE
665 FROM tst_manual_fb
666 WHERE active_fi = ' . $ilDB->quote($active_fi, 'integer') . '
667 AND pass = ' . $ilDB->quote($pass, 'integer')
668 );
669
670 if ($must_renumber) {
671 $ilDB->manipulate(
672 'UPDATE tst_manual_fb
673 SET pass = pass - 1
674 WHERE active_fi = ' . $ilDB->quote($active_fi, 'integer') . '
675 AND pass > ' . $ilDB->quote($pass, 'integer')
676 );
677 }
678
679 // tst_mark -> nothing to do
680 //
681 // tst_pass_result
682 $ilDB->manipulate(
683 'DELETE
684 FROM tst_pass_result
685 WHERE active_fi = ' . $ilDB->quote($active_fi, 'integer') . '
686 AND pass = ' . $ilDB->quote($pass, 'integer')
687 );
688
689 if ($must_renumber) {
690 $ilDB->manipulate(
691 'UPDATE tst_pass_result
692 SET pass = pass - 1
693 WHERE active_fi = ' . $ilDB->quote($active_fi, 'integer') . '
694 AND pass > ' . $ilDB->quote($pass, 'integer')
695 );
696 }
697
698 $ilDB->manipulate(
699 'DELETE
700 FROM tst_sequence
701 WHERE active_fi = ' . $ilDB->quote($active_fi, 'integer') . '
702 AND pass = ' . $ilDB->quote($pass, 'integer')
703 );
704
705 if ($must_renumber) {
706 $ilDB->manipulate(
707 'UPDATE tst_sequence
708 SET pass = pass - 1
709 WHERE active_fi = ' . $ilDB->quote($active_fi, 'integer') . '
710 AND pass > ' . $ilDB->quote($pass, 'integer')
711 );
712 }
713
714 // tst_solutions
715 $ilDB->manipulate(
716 'DELETE
717 FROM tst_solutions
718 WHERE active_fi = ' . $ilDB->quote($active_fi, 'integer') . '
719 AND pass = ' . $ilDB->quote($pass, 'integer')
720 );
721
722 if ($must_renumber) {
723 $ilDB->manipulate(
724 'UPDATE tst_solutions
725 SET pass = pass - 1
726 WHERE active_fi = ' . $ilDB->quote($active_fi, 'integer') . '
727 AND pass > ' . $ilDB->quote($pass, 'integer')
728 );
729 }
730
731 // tst_test_result
732 $ilDB->manipulate(
733 'DELETE
734 FROM tst_test_result
735 WHERE active_fi = ' . $ilDB->quote($active_fi, 'integer') . '
736 AND pass = ' . $ilDB->quote($pass, 'integer')
737 );
738
739 if ($must_renumber) {
740 $ilDB->manipulate(
741 'UPDATE tst_test_result
742 SET pass = pass - 1
743 WHERE active_fi = ' . $ilDB->quote($active_fi, 'integer') . '
744 AND pass > ' . $ilDB->quote($pass, 'integer')
745 );
746 }
747
748 // tst_test_rnd_qst -> nothing to do
749
750 // tst_times
751 $ilDB->manipulate(
752 'DELETE
753 FROM tst_times
754 WHERE active_fi = ' . $ilDB->quote($active_fi, 'integer') . '
755 AND pass = ' . $ilDB->quote($pass, 'integer')
756 );
757
758 if ($must_renumber) {
759 $ilDB->manipulate(
760 'UPDATE tst_times
761 SET pass = pass - 1
762 WHERE active_fi = ' . $ilDB->quote($active_fi, 'integer') . '
763 AND pass > ' . $ilDB->quote($pass, 'integer')
764 );
765 }
766
767 $this->test_result_repository->updateTestResultCache((int) $active_fi);
768
770 }
771
773 {
774 $this->ctrl->redirectByClass(ilTestParticipantsGUI::class);
775 }
776
777 protected function sendPage(string $page)
778 {
779 $this->http->saveResponse($this->http->response()->withBody(
780 Streams::ofString($page)
781 ));
782 $this->http->sendResponse();
783 $this->http->close();
784 }
785
786 protected function buildResultsTitle(string $fullname, int $pass): string
787 {
788 if ($this->object->getAnonymity()) {
789 return sprintf(
790 $this->lng->txt('tst_eval_results_by_pass_lo'),
791 $pass + 1
792 );
793 }
794 return sprintf(
795 $this->lng->txt('tst_result_user_name_pass'),
796 $pass + 1,
797 $fullname
798 );
799 }
800
801 private function buildAttemptComponents(
802 int $active_id,
803 int $attempt_id,
804 bool $with_test_results_overview,
805 bool $for_print
806 ): array {
807 $settings = $this->results_presentation_factory->getAttemptResultsSettings(
808 $this->object,
809 false
810 );
811 $attempt_overview = $this->ui_factory->panel()->sub(
812 $this->lng->txt('question_summary'),
813 $this->results_data_factory->getAttemptOverviewFor(
814 $settings,
815 $this->object,
816 $active_id,
817 $attempt_id
818 )->getAsDescriptiveListing(
819 $this->lng,
820 $this->ui_factory,
821 [
822 'timezone' => new DateTimeZone($this->user->getTimeZone()),
823 'datetimeformat' => $this->user->getDateTimeFormat()->toString()
824 ]
825 )
826 );
827
828 if ($with_test_results_overview) {
829 $attempt_overview = $attempt_overview->withFurtherInformation(
830 $this->ui_factory->card()->standard($this->lng->txt('overview'))->withSections([
831 $this->results_data_factory->getOverviewDataForTest($this->object)
832 ->getAsDescriptiveListing(
833 $this->lng,
834 $this->ui_factory
835 )
836 ])
837 );
838 }
839
840 $results_presentation_table = $this->results_presentation_factory->getAttemptResultsPresentationTable(
841 $this->results_data_factory->getAttemptResultsFor(
842 $settings,
843 $this->object,
844 $active_id,
845 $attempt_id,
846 false
847 ),
848 $settings,
849 '',
850 $for_print
851 )->getTableComponent();
852
853 if ($for_print) {
854 $signal = $results_presentation_table->getExpandAllSignal();
855 $results_presentation_table = [
856 $results_presentation_table,
857 $this->ui_factory->legacy('')->withAdditionalOnLoadCode(
858 fn(string $id): string => "$(document).trigger('{$signal->getId()}',"
859 . '{"options" : ' . json_encode($signal->getOptions()) . '}); '
860 )
861 ];
862 }
863
864
865
866 $attempt_details = $this->ui_factory->panel()->sub(
867 $this->lng->txt('details'),
868 $results_presentation_table
869 );
870
871 return [$attempt_overview, $attempt_details];
872 }
873
874 private function addPrintResultsButtonToToolbar(): void
875 {
876 $link = $this->ctrl->getLinkTargetByClass(self::class, 'printResults');
877 $this->toolbar->addComponent(
878 $this->ui_factory->button()->standard(
879 $this->lng->txt('print'),
880 ''
881 )->withOnLoadCode(
882 fn($id): string => "document.getElementById('{$id}').addEventListener('click', "
883 . "(e) => {window.open('{$link}');}"
884 . ');'
885 )
886 );
887 }
888
889 private function addPrintButtonToToolbar(): void
890 {
891 $this->toolbar->addComponent(
892 $this->ui_factory->button()->standard(
893 $this->lng->txt('print'),
894 ''
895 )->withOnLoadCode(
896 fn($id): string => "document.getElementById('{$id}').addEventListener('click', "
897 . "()=>{window.print();}"
898 . ');'
899 )
900 );
901 }
902
904 {
905 $this->toolbar->addComponent(
906 $this->ui_factory->button()->standard(
907 $this->lng->txt('certificate'),
908 $this->ctrl->getLinkTargetByClass(self::class, 'outCertificate')
909 )
910 );
911 }
912
914 {
915 if ($this->testrequest->isset('show_best_solutions')) {
917 'tst_results_show_best_solutions',
918 $this->testrequest->int('show_best_solutions') === 1
919 );
920 }
921
922 if (ilSession::get('tst_results_show_best_solutions')) {
923 $this->ctrl->setParameter($this, 'show_best_solutions', '0');
924 $label = $this->lng->txt('tst_btn_hide_best_solutions');
925 } else {
926 $this->ctrl->setParameter($this, 'show_best_solutions', '1');
927 $label = $this->lng->txt('tst_btn_show_best_solutions');
928 }
929
930 $this->toolbar->addSeparator();
931 $this->toolbar->addComponent(
932 $this->ui_factory->button()->standard(
933 $label,
934 $this->ctrl->getLinkTargetByClass(self::class, $this->ctrl->getCmd(self::DEFAULT_CMD))
935 )
936 );
937 $this->ctrl->clearParameters($this, 'show_best_solutions');
938 }
939
941 array $selected_active_ids,
942 int $current_active_id
943 ): void {
944 $this->toolbar->addSeparator();
945 $this->toolbar->addComponent(
946 $this->ui_factory->dropdown()
947 ->standard(
948 $this->buildParticipantSelectorArray($selected_active_ids, $current_active_id)
949 )->withLabel($this->lng->txt('tst_res_jump_to_participant_hint_opt'))
950 );
951 }
952
954 array $selected_active_ids,
955 int $current_active_id
956 ): array {
957 $this->ctrl->setParameterByClass(self::class, 'active_ids', implode(',', $selected_active_ids));
958 unset($selected_active_ids[array_search($current_active_id, $selected_active_ids)]);
959 $available_user_links = array_map(
960 function (int $v): StandardLink {
961 $this->ctrl->setParameterByClass(self::class, 'active_id', $v);
962 return $this->ui_factory->link()->standard(
963 ilObjUser::_lookupFullname($this->object->_getUserIdFromActiveId($v)),
964 $this->ctrl->getLinkTargetByClass(self::class, 'showResults')
965 );
966 },
967 $selected_active_ids
968 );
969 $this->ctrl->clearParameterByClass(self::class, 'active_id');
970 $this->ctrl->clearParameterByClass(self::class, 'active_ids');
971 return $available_user_links;
972 }
973
975 array $available_attempts,
976 int $selected_attempt
977 ): void {
978 $selected_attempt++;
979 $this->toolbar->addComponent(
980 $this->buildAttemptSwitchingViewControl(
981 $available_attempts,
982 $selected_attempt
983 )
984 );
985 $this->ctrl->clearParameterByClass(self::class, 'attempt');
986 }
987
989 array $available_attempts,
990 int $selected_attempt
991 ): ViewControlMode {
992 return $this->ui_factory->viewControl()->mode(
993 array_reduce(
994 $available_attempts,
995 function (array $c, int $v): array {
996 $this->ctrl->setParameterByClass(self::class, 'attempt', $v);
997 $attempt = $v + 1;
998 $c["{$this->lng->txt('tst_attempt')} {$attempt}"] = $this
999 ->ctrl->getLinkTargetByClass(self::class, $this->ctrl->getCmd(self::DEFAULT_CMD));
1000 return $c;
1001 },
1002 []
1003 ),
1004 $this->lng->txt('select_attempt')
1005 )->withActive("{$this->lng->txt('tst_attempt')} {$selected_attempt}");
1006 }
1007}
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
$components
Stream factory which enables the user to create streams without the knowledge of the concrete class.
Definition: Streams.php:32
Validates if an active certificate is stored in the database and can be downloaded by the user.
Just a wrapper class to create Unit Test for other classes.
static getInstance(ilTestSession $a_test_session)
static getContentStylePath(int $a_style_id, bool $add_random=true, bool $add_token=true)
get content style path static (to avoid full reading)
static _getResultPass($active_id)
Retrieves the pass number that should be counted for a given user.
static lookupExamId($active_id, $pass)
static _lookupFullname(int $a_user_id)
static get(string $a_var)
static set(string $a_var, $a_val)
Set a value.
ILIAS Setting Class.
special template class to simplify handling of ITX/PEAR
Output class for assessment test evaluation.
addParticipantSelectorToToolbar(array $selected_active_ids, int $current_active_id)
__construct(ilObjTest $object)
getEvaluationQuestionId($question_id, $original_id='')
Returns the ID of a question for evaluation purposes.
buildParticipantSelectorArray(array $selected_active_ids, int $current_active_id)
ilTestProcessLockerFactory $processLockerFactory
buildAttemptSwitchingViewControl(array $available_attempts, int $selected_attempt)
addAttemptSwitchingViewControlToToolbar(array $available_attempts, int $selected_attempt)
buildResultsTitle(string $fullname, int $pass)
buildAttemptComponents(int $active_id, int $attempt_id, bool $with_test_results_overview, bool $for_print)
redirectToPassDeletionContext(string $context)
Base Exception for all Exceptions relating to Modules/Test.
Service GUI class for tests.
buildPassOverviewTableGUI(ilTestEvaluationGUI $target_gui)
setContextResultPresentation(bool $contextResultPresentation)
buildQuestionRelatedObjectivesList(ilLOTestQuestionAdapter $objectives_adapter, ilTestQuestionSequence $test_sequence)
getResultsSignature()
Returns HTML code for a signature field.
populatePassFinishDate(ilTemplate $tpl, ?int $pass_finish_date)
getPassListOfAnswers(&$result_array, $active_id, $pass, $show_solutions=false, $only_answered_questions=false, $show_question_only=false, $show_reached_points=false, $anchorNav=false, ?ilTestQuestionRelatedObjectivesList $objectives_list=null, ?ResultsTitlesBuilder $testResultHeaderLabelBuilder=null)
Returns the list of answers of a users test pass.
populateExamId(ilTemplate $tpl, int $active_id, int $pass)
readonly ilDBInterface $db
ilGlobalTemplateInterface ilTemplate $tpl
sk 2023-08-01: We need this union type, even if it is wrong! To change this
readonly ilSetting $settings
getAdditionalUsrDataHtmlAndPopulateWindowTitle($testSession, $active_id, $overwrite_anonymity=false)
Returns the user data for a test results output.
getPassOverviewTableData(ilTestSession $test_session, array $passes, bool $with_results)
getGradingMessageBuilder(int $active_id)
static getStyleSheetLocation(string $mode="output", string $a_css_name="")
get full style sheet file name (path inclusive) of current user
$c
Definition: deliver.php:25
return['delivery_method'=> 'php',]
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
setVariable(string $variable, $value='')
Sets the given variable to the given value.
parseCurrentBlock(string $block_name=self::DEFAULT_BLOCK)
Parses the given block.
setCurrentBlock(string $part=self::DEFAULT_BLOCK)
Sets the template to the given block.
get(string $part=self::DEFAULT_BLOCK)
Renders the given block and returns the html string.
This describes a Sub Panel.
Definition: Sub.php:30
This describes a Mode Control.
Definition: Mode.php:29
static http()
Fetches the global http state from ILIAS.
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
$context
Definition: webdav.php:31