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