diff --git a/Modules/Test/classes/Results/class.ilQuestionResult.php b/Modules/Test/classes/Results/class.ilQuestionResult.php
new file mode 100644
index 000000000000..1de0a45ad2ad
--- /dev/null
+++ b/Modules/Test/classes/Results/class.ilQuestionResult.php
@@ -0,0 +1,104 @@
+id;
+ }
+ public function getType(): string
+ {
+ return $this->type;
+ }
+ public function getTitle(): string
+ {
+ return $this->title;
+ }
+ public function getUserAnswer(): string
+ {
+ return $this->usr_solution;
+ }
+ public function getBestSolution(): string
+ {
+ return $this->best_solution;
+ }
+ public function getQuestionScore(): float
+ {
+ return $this->question_score;
+ }
+ public function getUserScore(): float
+ {
+ return $this->usr_score;
+ }
+ public function getUserScorePercent(): float
+ {
+ return 100 / $this->getQuestionScore() * $this->getUserScore();
+ }
+ public function getCorrect(): int
+ {
+ if ($this->getUserScore() === 0.0) {
+ return self::CORRECT_NONE;
+ }
+ if ($this->getUserScore() === $this->getQuestionScore()) {
+ return self::CORRECT_FULL;
+ }
+ return self::CORRECT_PARTIAL;
+ }
+ public function getFeedback(): string
+ {
+ return $this->feedback;
+ }
+ public function isWorkedThrough(): bool
+ {
+ return $this->workedthrough;
+ }
+ public function isAnswered(): bool
+ {
+ return $this->answered;
+ }
+ public function getContentForRecapitulation(): ?string
+ {
+ return $this->content_for_recapitulation;
+ }
+}
diff --git a/Modules/Test/classes/Results/class.ilTestPassResult.php b/Modules/Test/classes/Results/class.ilTestPassResult.php
new file mode 100644
index 000000000000..8183a25d9168
--- /dev/null
+++ b/Modules/Test/classes/Results/class.ilTestPassResult.php
@@ -0,0 +1,60 @@
+settings;
+ }
+
+ public function getActiveId(): int
+ {
+ return $this->active_id;
+ }
+
+ public function getPass(): int
+ {
+ return $this->pass_id;
+ }
+
+ /**
+ * @return ilQuestionResult[];
+ */
+ public function getQuestionResults(): array
+ {
+ return $this->question_results;
+ }
+}
diff --git a/Modules/Test/classes/Results/class.ilTestPassResultsSettings.php b/Modules/Test/classes/Results/class.ilTestPassResultsSettings.php
new file mode 100644
index 000000000000..ee38a967a432
--- /dev/null
+++ b/Modules/Test/classes/Results/class.ilTestPassResultsSettings.php
@@ -0,0 +1,66 @@
+show_hidden_questions;
+ }
+
+ public function getShowOptionalQuestions(): bool
+ {
+ return $this->show_optional_questions;
+ }
+
+ public function getShowBestSolution(): bool
+ {
+ return $this->show_best_solution;
+ }
+
+ public function getShowFeedback(): bool
+ {
+ return $this->show_feedback;
+ }
+
+ public function getQuestionTextOnly(): bool
+ {
+ return $this->question_text_only;
+ }
+
+ public function getShowRecapitulation(): bool
+ {
+ return $this->show_recapitulation;
+ }
+}
diff --git a/Modules/Test/classes/Results/class.ilTestPassResultsTable.php b/Modules/Test/classes/Results/class.ilTestPassResultsTable.php
new file mode 100644
index 000000000000..589e1ad03225
--- /dev/null
+++ b/Modules/Test/classes/Results/class.ilTestPassResultsTable.php
@@ -0,0 +1,246 @@
+getViewControlsParameter();
+ $results = $this->applyControls($mode, $sortation, $test_results->getQuestionResults());
+ $target = new URLBuilder($data_factory->uri($http->request()->getUri()->__toString()));
+
+ $this->table = $ui_factory->table()->presentation(
+ $title,
+ $this->getViewControls($ui_factory, $lng, $target, $mode, $sortation),
+ $this->getMapping()
+ )
+ ->withEnvironment([
+ self::ENV => $test_results->getSettings(),
+ self::LNG => $lng
+ ])
+ ->withData($results);
+ }
+
+ public function render(): string
+ {
+ return $this->ui_renderer->render($this->table);
+ }
+
+ /**
+ * @param ilQuestionResult[] $question_results
+ */
+ protected function applyControls(
+ string $mode,
+ string $sortation,
+ array $question_results
+ ) {
+ switch($mode) {
+ case self::MODE_OPT_CORRECT:
+ $filter = static fn($qr) => $qr->getCorrect() === ilQuestionResult::CORRECT_FULL;
+ break;
+ case self::MODE_OPT_INCORRECT:
+ $filter = static fn($qr) => $qr->getCorrect() !== ilQuestionResult::CORRECT_FULL;
+ break;
+ case self::MODE_OPT_ALL:
+ default:
+ $filter = static fn($qr) => true;
+ }
+ $question_results = array_filter($question_results, $filter);
+
+ if ($sortation === self::SORT_OPT_POSSIBLESCORE) {
+ usort(
+ $question_results,
+ static fn(ilQuestionResult $a, ilQuestionResult $b) => $a->getQuestionScore() <=> $b->getQuestionScore()
+ );
+ $question_results = array_reverse($question_results);
+ }
+ return $question_results;
+ }
+
+ protected function getViewControlsParameter(): array
+ {
+ $request = $this->http->wrapper()->query();
+ $pre = implode(URLBuilder::SEPARATOR, self::URL_NAMESPACE) . URLBuilder::SEPARATOR;
+
+ $mode = $request->has($pre . self::PARAM_MODE) ?
+ $request->retrieve($pre . self::PARAM_MODE, $this->refinery->kindlyTo()->string()) : self::MODE_OPT_ALL;
+
+ $sortation = $request->has($pre . self::PARAM_SORT) ?
+ $request->retrieve($pre . self::PARAM_SORT, $this->refinery->kindlyTo()->string()) : self::SORT_OPT_ORDEROFAPPEARANCE;
+
+ return [$mode, $sortation];
+ }
+
+ /**
+ * return \ILIAS\UI\ViewControl\ViewControl[]
+ */
+ protected function getViewControls(
+ UIFactory $ui_factory,
+ ilLanguage $lng,
+ URLBuilder $target,
+ string $mode,
+ string $sortation
+ ): array {
+ $builder = $target->acquireParameter(self::URL_NAMESPACE, self::PARAM_MODE);
+ [$target, $token] = $builder;
+
+ $modes = [
+ $lng->txt('resulttable_all') => $target->withParameter($token, self::MODE_OPT_ALL)->buildURI()->__toString(),
+ $lng->txt('resulttable_correct') => $target->withParameter($token, self::MODE_OPT_CORRECT)->buildURI()->__toString(),
+ $lng->txt('resulttable_incorrect') => $target->withParameter($token, self::MODE_OPT_INCORRECT)->buildURI()->__toString(),
+ ];
+ $check = [self::MODE_OPT_ALL, self::MODE_OPT_CORRECT, self::MODE_OPT_INCORRECT];
+ $active = array_search($mode, $check);
+
+ $vc_mode = $ui_factory->viewControl()->mode($modes, $lng->txt('ta_resulttable_vc_mode_aria'))
+ ->withActive(array_keys($modes)[$active]);
+
+ $options = [
+ self::SORT_OPT_ORDEROFAPPEARANCE => $lng->txt('resulttable_vc_sort_iooa'),
+ self::SORT_OPT_POSSIBLESCORE => $lng->txt('resulttable_vc_sort_posscore')
+ ];
+
+ $pre = implode(URLBuilder::SEPARATOR, self::URL_NAMESPACE) . URLBuilder::SEPARATOR;
+ $vc_sort = $ui_factory->viewControl()->sortation($options)->withTargetURL(
+ $target->buildURI()->__toString(),
+ $pre . self::PARAM_SORT
+ )
+ ->withLabel($options[$sortation]);
+
+ return [
+ $vc_mode,
+ $vc_sort
+ ];
+ }
+
+ protected function getMapping(): \Closure
+ {
+ return function ($row, $question, $ui_factory, $environment) {
+ $env = $environment[self::ENV];
+ $lng = $environment[self::LNG];
+
+ $title = sprintf(
+ '%s [ID: %s]',
+ $question->getTitle(),
+ (string)$question->getId()
+ );
+
+ $important_fields = [
+ $lng->txt('question_id') => (string)$question->getId(),
+ $lng->txt('question_type') => $question->getType(),
+ $lng->txt('points') => sprintf(
+ '%s/%s (%s%%)',
+ (string)$question->getUserScore(),
+ (string)$question->getQuestionScore(),
+ (string)$question->getUserScorePercent()
+ )
+ ];
+ $stats = $ui_factory->listing()->characteristicValue()->text($important_fields);
+ $user_answer = $question->getUserAnswer();
+ $best_solution = $env->getShowBestSolution() ? $question->getBestSolution() : '';
+
+
+ $feedback = $ui_factory->listing()->descriptive([
+ $lng->txt('tst_feedback') => $question->getFeedback()
+ ]);
+
+ $contents = [];
+
+ $contents[] = $stats;
+ if ($env->getShowFeedback()) {
+ $contents[] = $feedback;
+ }
+
+ if ($recap = $question->getContentForRecapitulation()) {
+ $contents[] = $ui_factory->listing()->descriptive([
+ $lng->txt('suggested_solution') => $recap
+ ]);
+ }
+
+
+ $answers = $ui_factory->layout()->alignment()->horizontal()->evenlyDistributed(
+ $ui_factory->listing()->descriptive([$lng->txt('tst_header_participant') => $user_answer]),
+ $ui_factory->listing()->descriptive([$lng->txt('tst_header_solution') => $best_solution])
+ );
+ $contents[] = $answers;
+
+ $content = $ui_factory->layout()->alignment()->vertical(...$contents);
+
+ switch($question->getCorrect()) {
+ case ilQuestionResult::CORRECT_FULL:
+ $icon_name = 'icon_ok.svg';
+ $label = $lng->txt("answer_is_right");
+ break;
+ case ilQuestionResult::CORRECT_PARTIAL:
+ $icon_name = 'icon_mostly_ok.svg';
+ $label = $lng->txt("answer_is_not_correct_but_positive");
+ break;
+ case ilQuestionResult::CORRECT_NONE:
+ $icon_name = 'icon_not_ok.svg';
+ $label = $lng->txt("answer_is_wrong");
+ break;
+ }
+ $path = ilUtil::getImagePath('standard/' . $icon_name);
+ $correct_icon = $ui_factory->symbol()->icon()->custom(
+ $path,
+ $label
+ );
+
+ return $row
+ ->withHeadline($title)
+ ->withLeadingSymbol($correct_icon)
+ ->withImportantFields($important_fields)
+ ->withContent($content);
+ };
+ }
+}
diff --git a/Modules/Test/classes/Results/class.ilTestResultsFactory.php b/Modules/Test/classes/Results/class.ilTestResultsFactory.php
new file mode 100644
index 000000000000..8378ed0fbc0b
--- /dev/null
+++ b/Modules/Test/classes/Results/class.ilTestResultsFactory.php
@@ -0,0 +1,192 @@
+getPassResultsSettings($test_obj, $is_user_output);
+ return $this->buildPassResults(
+ $settings,
+ $test_obj,
+ $active_id,
+ $pass_id,
+ $is_user_output
+ );
+ }
+
+ protected function buildPassResults(
+ ilTestPassResultsSettings $settings,
+ ilObjTest $test_obj,
+ int $active_id,
+ int $pass_id,
+ bool $is_user_output
+ ): ilTestPassResult {
+ $question_results = [];
+
+ $results = $test_obj->getTestResult(
+ $active_id,
+ $pass_id,
+ false, //$ordered_sequence
+ $settings->getShowHiddenQuestions(),
+ $settings->getShowOptionalQuestions()
+ );
+
+ // params of getSolutionOutput
+ $graphical_output = false;
+ $result_output = false;
+ $show_question_only = $settings->getQuestionTextOnly();
+ $show_feedback = false; //general
+ $show_correct_solution = false;
+ $show_manual_scoring = false;
+ $show_question_text = true;
+ $show_inline_feedback = true;
+
+ foreach ($results as $idx => $qresult) {
+ if (!is_numeric($idx)) {
+ continue;
+ }
+
+ $qid = $qresult['qid'];
+ $type = $qresult['type'];
+ $title = $qresult['title'];
+ $question_score = $qresult['max'];
+ $usr_score = $qresult['reached'];
+ $workedthrough = (bool)$qresult['workedthrough'];
+ $answered = (bool)$qresult['answered'];
+
+ $question_gui = $test_obj->createQuestionGUI("", $qid);
+ $shuffle_trafo = $this->shuffler->getAnswerShuffleFor($qid, $active_id, $pass_id);
+ $question_gui->object->setShuffler($shuffle_trafo);
+
+ $graphical_output = true;
+ $show_correct_solution = false;
+ $show_inline_feedback = $settings->getShowFeedback();
+ $usr_solution = $question_gui->getSolutionOutput(
+ $active_id,
+ $pass_id,
+ $graphical_output,
+ $result_output,
+ $show_question_only,
+ $show_feedback,
+ $show_correct_solution,
+ $show_manual_scoring,
+ $show_question_text,
+ $show_inline_feedback
+ );
+
+ $graphical_output = false;
+ $show_correct_solution = true;
+ $show_inline_feedback = false;
+ $best_solution = $question_gui->getSolutionOutput(
+ $active_id,
+ $pass_id,
+ $graphical_output,
+ $result_output,
+ $show_question_only,
+ $show_feedback,
+ $show_correct_solution,
+ $show_manual_scoring,
+ $show_question_text,
+ $show_inline_feedback
+ );
+
+ if ($show_question_only) {
+ $usr_solution = $this->ui_renderer->render($this->ui_factory->legacy('' . $usr_solution . '
'));
+ $best_solution = $this->ui_renderer->render($this->ui_factory->legacy('' . $best_solution . '
'));
+ }
+
+ $feedback = $question_gui->getGenericFeedbackOutput($active_id, $pass_id);
+
+ $recapitulation = null;
+ if ($is_user_output && $settings->getShowRecapitulation()) {
+ $recapitulation = $question_gui->object->getSuggestedSolutionOutput();
+ }
+
+ $question_results[] = new ilQuestionResult(
+ $qid,
+ $type,
+ $title,
+ $question_score,
+ $usr_score,
+ $usr_solution,
+ $best_solution,
+ $feedback,
+ $workedthrough,
+ $answered,
+ $recapitulation
+ );
+ }
+
+ return new ilTestPassResult(
+ $settings,
+ $active_id,
+ $pass_id,
+ $question_results
+ );
+ }
+
+ protected function getPassResultsSettings(
+ ilObjTest $test_obj,
+ bool $is_user_output
+ ): ilTestPassResultsSettings {
+ $settings = $test_obj->getScoreSettings();
+ $settings_summary = $settings->getResultSummarySettings();
+ $settings_result = $settings->getResultDetailsSettings();
+
+ $show_hidden_questions = false;
+ $show_optional_questions = true;
+ $show_best_solution = $is_user_output ?
+ $settings_result->getShowSolutionListComparison() :
+ (bool)ilSession::get('tst_results_show_best_solutions');
+ $show_feedback = $settings_result->getShowSolutionFeedback();
+ $show_question_text_only = $settings_result->getShowSolutionAnswersOnly();
+ $show_content_for_recapitulation = $settings_result->getShowSolutionSuggested();
+
+ return new ilTestPassResultsSettings(
+ $show_hidden_questions,
+ $show_optional_questions,
+ $show_best_solution,
+ $show_feedback,
+ $show_question_text_only,
+ $show_content_for_recapitulation
+ );
+ }
+}
diff --git a/Modules/Test/classes/Results/class.ilTestResultsPresentationFactory.php b/Modules/Test/classes/Results/class.ilTestResultsPresentationFactory.php
new file mode 100644
index 000000000000..286437be7d99
--- /dev/null
+++ b/Modules/Test/classes/Results/class.ilTestResultsPresentationFactory.php
@@ -0,0 +1,58 @@
+ui_factory,
+ $this->ui_renderer,
+ $this->refinery,
+ $this->http,
+ $this->data_factory,
+ $this->lng,
+ $pass_results,
+ $title
+ );
+ }
+}
diff --git a/Modules/Test/classes/ScoreReporting/class.ilObjTestScoreSettingsDatabaseRepository.php b/Modules/Test/classes/ScoreReporting/class.ilObjTestScoreSettingsDatabaseRepository.php
index 74ed43602466..5779ae49ba9d 100644
--- a/Modules/Test/classes/ScoreReporting/class.ilObjTestScoreSettingsDatabaseRepository.php
+++ b/Modules/Test/classes/ScoreReporting/class.ilObjTestScoreSettingsDatabaseRepository.php
@@ -98,7 +98,6 @@ protected function doSelect(string $where_part): ilObjTestScoreSettings
//->withShowPassDetails derived from results_presentation with bit RESULTPRES_BIT_PASS_DETAILS
(new ilObjTestSettingsResultDetails($test_id))
->withResultsPresentation((int)$row['results_presentation'])
- ->withPrintBestSolutionWithResult((bool) $row['print_bs_with_res'])
->withShowExamIdInTestResults((bool) $row['examid_in_test_res'])
->withExportSettings((int) $row['exportsettings'])
->withTaxonomyFilterIds($tax_filter_ids),
diff --git a/Modules/Test/classes/ScoreReporting/ilObjTestSettingsResultDetails.php b/Modules/Test/classes/ScoreReporting/ilObjTestSettingsResultDetails.php
index a91fef9c7a8d..33936d68cd84 100644
--- a/Modules/Test/classes/ScoreReporting/ilObjTestSettingsResultDetails.php
+++ b/Modules/Test/classes/ScoreReporting/ilObjTestSettingsResultDetails.php
@@ -52,45 +52,6 @@ public function toForm(
Refinery $refinery,
array $environment = null
): FormInput {
- $bool_with_optional_addition = $refinery->custom()->transformation(
- function ($v) {
- if (!$v) {
- return [false, false]; //[enabled, show_best_solution]
- }
- return [true, array_shift($v)];
- }
- );
-
- $optgroup_lists = $f->optionalGroup(
- [
- $f->checkbox(
- $lng->txt('tst_results_print_best_solution'),
- $lng->txt('tst_results_print_best_solution_info')
- )->withValue($this->getShowSolutionListComparison())
- ],
- $lng->txt('tst_show_solution_details'),
- $lng->txt('tst_show_solution_details_desc')
- )->withAdditionalTransformation($bool_with_optional_addition);
-
- if (!$this->getShowSolutionListOwnAnswers()) {
- $optgroup_lists = $optgroup_lists->withValue(null);
- }
-
- $optgroup_singlepage = $f->optionalGroup(
- [
- $f->checkbox(
- $lng->txt('tst_results_print_best_solution_singlepage'),
- $lng->txt('tst_results_print_best_solution_singlepage_info')
- )->withValue($this->getPrintBestSolutionWithResult())
- ],
- $lng->txt('tst_show_solution_details_singlepage'),
- $lng->txt('tst_show_solution_details_singlepage_desc')
- )->withAdditionalTransformation($bool_with_optional_addition);
- if (!$this->getShowSolutionDetails()) {
- $optgroup_singlepage = $optgroup_singlepage->withValue(null);
- }
-
-
$taxonomy_options = $environment['taxonomy_options'];
$taxonomy_ids = $f->multiselect(
$lng->txt('tst_results_tax_filters'),
@@ -99,9 +60,11 @@ function ($v) {
);
$fields = [
- 'solution_details' => $optgroup_lists,
- 'solution_details_singlepage' => $optgroup_singlepage,
-
+ 'solution_best_solution' =>
+ $f->checkbox(
+ $lng->txt('tst_results_print_best_solution'),
+ $lng->txt('tst_results_print_best_solution_info')
+ )->withValue($this->getShowSolutionListComparison()),
'solution_feedback' => $f->checkbox(
$lng->txt('tst_show_solution_feedback'),
$lng->txt('tst_show_solution_feedback_desc')
@@ -138,13 +101,8 @@ function ($v) {
->withAdditionalTransformation(
$refinery->custom()->transformation(
function ($v) {
- list($solution_list_details, $solution_list_best_solution) = $v['solution_details'];
- list($solution_sp_details, $solution_sp_best_solution) = $v['solution_details_singlepage'];
return (clone $this)
- ->withShowSolutionListOwnAnswers($solution_list_details)
- ->withShowSolutionListComparison($solution_list_best_solution)
- ->withShowSolutionDetails($solution_sp_details)
- ->withPrintBestSolutionWithResult($solution_sp_best_solution)
+ ->withShowSolutionListComparison($v['solution_best_solution'])
->withShowSolutionFeedback($v['solution_feedback'])
->withShowSolutionSuggested($v['solution_suggested'])
->withShowSolutionPrintview($v['solution_printview'])
@@ -160,7 +118,6 @@ function ($v) {
public function toStorage(): array
{
return [
- 'print_bs_with_res' => ['integer', (int) $this->getPrintBestSolutionWithResult()],
'results_presentation' => ['integer', $this->getResultsPresentation()],
'examid_in_test_res' => ['integer', (int) $this->getShowExamIdInTestResults()],
'exportsettings' => ['integer', (int) $this->getExportSettings()],
@@ -169,18 +126,6 @@ public function toStorage(): array
];
}
-
- public function getPrintBestSolutionWithResult(): bool
- {
- return $this->print_bs_with_res;
- }
- public function withPrintBestSolutionWithResult(bool $print_bs_with_res): self
- {
- $clone = clone $this;
- $clone->print_bs_with_res = $print_bs_with_res;
- return $clone;
- }
-
public function getResultsPresentation(): int
{
return $this->results_presentation;
@@ -232,15 +177,6 @@ public function withShowPassDetails(bool $flag): self
return $this->modifyResultPresentation(self::RESULTPRES_BIT_PASS_DETAILS, $flag);
}
- public function getShowSolutionDetails(): bool
- {
- return $this->compareResultPresentation(self::RESULTPRES_BIT_SOLUTION_DETAILS);
- }
- public function withShowSolutionDetails(bool $flag): self
- {
- return $this->modifyResultPresentation(self::RESULTPRES_BIT_SOLUTION_DETAILS, $flag);
- }
-
public function getShowSolutionPrintview(): bool
{
return $this->compareResultPresentation(self::RESULTPRES_BIT_SOLUTION_PRINTVIEW);
@@ -295,15 +231,6 @@ public function withShowSolutionListComparison(bool $flag): self
return $this->modifyResultPresentation(self::RESULTPRES_BIT_SOLUTION_LISTCOMPARE, $flag);
}
- public function getShowSolutionListOwnAnswers(): bool
- {
- return $this->compareResultPresentation(self::RESULTPRES_BIT_SOLUTION_LISTOWNANSWERS);
- }
- public function withShowSolutionListOwnAnswers(bool $flag): self
- {
- return $this->modifyResultPresentation(self::RESULTPRES_BIT_SOLUTION_LISTOWNANSWERS, $flag);
- }
-
public function getExportSettings(): int
{
return $this->exportsettings;
diff --git a/Modules/Test/classes/class.ilObjTest.php b/Modules/Test/classes/class.ilObjTest.php
index a33265909211..c071dea0d3b0 100755
--- a/Modules/Test/classes/class.ilObjTest.php
+++ b/Modules/Test/classes/class.ilObjTest.php
@@ -134,8 +134,10 @@ public function __construct(int $id = 0, bool $a_call_by_reference = true)
$this->component_repository = $DIC['component.repository'];
$this->component_factory = $DIC['component.factory'];
$this->filesystem_web = $DIC->filesystem()->web();
- $this->testManScoringDoneHelper = new TestManScoringDoneHelper();
- $this->participant_access_filter = new ilTestParticipantAccessFilterFactory($DIC['ilAccess']);
+
+ $local_dic = $this->getLocalDIC();
+ $this->participant_access_filter = $local_dic['participantAccessFilterFactory'];
+ $this->testManScoringDoneHelper = $local_dic['manScoringDoneHelper'];
$this->mark_schema = new ASS_MarkSchema($DIC['ilDB'], $DIC['lng'], $DIC['ilUser']->getId());
$this->mark_schema->createSimpleSchema(
@@ -166,6 +168,11 @@ public function __construct(int $id = 0, bool $a_call_by_reference = true)
);
}
+ public function getLocalDIC(): ILIAS\DI\Container
+ {
+ return ilTestDIC::dic();
+ }
+
/**
* returns the object title prepared to be used as a filename
*/
@@ -3875,15 +3882,6 @@ public function toXML(): string
$a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $this->getScoreReporting()));
$a_xml_writer->xmlEndTag("qtimetadatafield");
- $a_xml_writer->xmlStartTag("qtimetadatafield");
- $a_xml_writer->xmlElement("fieldlabel", null, "question_list");
- $a_xml_writer->xmlElement("fieldentry", null, sprintf("%d", $main_settings->getParticipantFunctionalitySettings()->getQuestionListEnabled()));
- $a_xml_writer->xmlEndTag("qtimetadatafield");
-
- $a_xml_writer->xmlStartTag("qtimetadatafield");
- $a_xml_writer->xmlElement("fieldlabel", null, "solution_details");
- $a_xml_writer->xmlElement("fieldentry", null, (int) $this->getShowSolutionDetails());
- $a_xml_writer->xmlEndTag("qtimetadatafield");
$a_xml_writer->xmlStartTag("qtimetadatafield");
$a_xml_writer->xmlElement("fieldlabel", null, "print_bs_with_res");
$a_xml_writer->xmlElement("fieldentry", null, (int) $this->getShowSolutionDetails() ? (int) $this->isBestSolutionPrintedWithResult() : 0);
@@ -5916,14 +5914,6 @@ public function getShowPassDetails(): bool
return $this->getScoreSettings()->getResultDetailsSettings()->getShowPassDetails();
}
- /**
- * Returns if the solution details should be presented to the user or not
- */
- public function getShowSolutionDetails(): bool
- {
- return $this->getScoreSettings()->getResultDetailsSettings()->getShowSolutionDetails();
- }
-
/**
* Returns if the solution printview should be presented to the user or not
*/
diff --git a/Modules/Test/classes/class.ilObjTestGUI.php b/Modules/Test/classes/class.ilObjTestGUI.php
index b360047b6834..c23501cb1a7e 100755
--- a/Modules/Test/classes/class.ilObjTestGUI.php
+++ b/Modules/Test/classes/class.ilObjTestGUI.php
@@ -121,6 +121,7 @@ public function __construct($refId = null)
$this->questioninfo = $DIC->testQuestionPool()->questionInfo();
$this->type = 'tst';
$this->testrequest = $DIC->test()->internal()->request();
+
$ref_id = 0;
if ($this->testrequest->hasRefId() && is_numeric($this->testrequest->getRefId())) {
$ref_id = $this->testrequest->getRefId();
diff --git a/Modules/Test/classes/class.ilTestDIC.php b/Modules/Test/classes/class.ilTestDIC.php
new file mode 100644
index 000000000000..1673e4a99fa4
--- /dev/null
+++ b/Modules/Test/classes/class.ilTestDIC.php
@@ -0,0 +1,75 @@
+
+ new ilTestShuffler($dic['refinery']);
+
+ $dic['factory.results'] = static fn($c): ilTestResultsFactory =>
+ new ilTestResultsFactory(
+ $c['shuffler'],
+ $dic['ui.factory'],
+ $dic['ui.renderer']
+ );
+
+ $dic['factory.results_presentation'] = static fn($c): ilTestResultsPresentationFactory =>
+ new ilTestResultsPresentationFactory(
+ $dic['ui.factory'],
+ $dic['ui.renderer'],
+ $dic['refinery'],
+ new ILIAS\Data\Factory(),
+ $dic['http'],
+ $dic['lng']
+ );
+
+
+ $dic['participantAccessFilterFactory'] = static fn($c): ilTestParticipantAccessFilterFactory =>
+ new ilTestParticipantAccessFilterFactory($dic['ilAccess']);
+
+ $dic['manScoringDoneHelper'] = static fn($c): TestManScoringDoneHelper =>
+ new TestManScoringDoneHelper();
+
+ $dic['request.internal'] = static fn($c): InternalRequestService =>
+ new InternalRequestService($dic['http'], $dic['refinery']);
+
+ return $dic;
+ }
+}
diff --git a/Modules/Test/classes/class.ilTestEvaluationGUI.php b/Modules/Test/classes/class.ilTestEvaluationGUI.php
index c211d77fe3e8..28f0b957c166 100644
--- a/Modules/Test/classes/class.ilTestEvaluationGUI.php
+++ b/Modules/Test/classes/class.ilTestEvaluationGUI.php
@@ -48,8 +48,6 @@ class ilTestEvaluationGUI extends ilTestServiceGUI
protected ilTestAccess $testAccess;
protected ilTestProcessLockerFactory $processLockerFactory;
- protected ilTestParticipantAccessFilterFactory $participant_access_filter;
-
/**
* ilTestEvaluationGUI constructor
*
@@ -64,6 +62,7 @@ public function __construct(ilObjTest $object)
global $DIC;
$this->participant_access_filter = new ilTestParticipantAccessFilterFactory($this->access);
$this->ui = $DIC->ui();
+
$this->processLockerFactory = new ilTestProcessLockerFactory(
new ilSetting('assessment'),
$this->db
@@ -331,6 +330,7 @@ public function outEvaluation()
}
$this->tpl->addCss(ilUtil::getStyleSheetLocation("output", "test_print.css", "Modules/Test"), "print");
+
if ($this->object->getShowSolutionAnswersOnly()) {
$this->tpl->addCss(ilUtil::getStyleSheetLocation("output", "test_print_hide_content.css", "Modules/Test"), "print");
}
@@ -863,47 +863,6 @@ public function outParticipantsPassDetails()
);
}
- $testResultHeaderLabelBuilder = new ilTestResultHeaderLabelBuilder($this->lng, $ilObjDataCache);
-
- $objectivesList = null;
-
- if ($this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired()) {
- $testSequence = $this->testSequenceFactory->getSequenceByActiveIdAndPass($active_id, $pass);
- $testSequence->loadFromDb();
- $testSequence->loadQuestions();
-
- $objectivesAdapter = ilLOTestQuestionAdapter::getInstance($testSession);
-
- $objectivesList = $this->buildQuestionRelatedObjectivesList($objectivesAdapter, $testSequence);
- $objectivesList->loadObjectivesTitles();
-
- $testResultHeaderLabelBuilder->setObjectiveOrientedContainerId($testSession->getObjectiveOrientedContainerId());
- $testResultHeaderLabelBuilder->setUserId($testSession->getUserId());
- $testResultHeaderLabelBuilder->setTestObjId($this->object->getId());
- $testResultHeaderLabelBuilder->setTestRefId($this->object->getRefId());
- $testResultHeaderLabelBuilder->initObjectiveOrientedMode();
- }
-
- $result_array = $this->getFilteredTestResult($active_id, $pass, false, !$this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired());
-
- $overviewTableGUI = $this->getPassDetailsOverviewTableGUI(
- $result_array,
- $active_id,
- $pass,
- $this,
- "outParticipantsPassDetails",
- '',
- true,
- $objectivesList
- );
- $overviewTableGUI->setTitle($testResultHeaderLabelBuilder->getPassDetailsHeaderLabel($pass + 1));
- $user_data = $this->getAdditionalUsrDataHtmlAndPopulateWindowTitle($testSession, $active_id, false);
- $user_id = $this->object->_getUserIdFromActiveId($active_id);
-
- $template = new ilTemplate("tpl.il_as_tst_pass_details_overview_participants.html", true, true, "Modules/Test");
-
- $toolbar = $this->buildUserTestResultsToolbarGUI();
-
if ($this->testrequest->isset('show_best_solutions')) {
ilSession::set('tst_results_show_best_solutions', true);
} elseif ($this->testrequest->isset('hide_best_solutions')) {
@@ -912,6 +871,18 @@ public function outParticipantsPassDetails()
ilSession::clear('tst_results_show_best_solutions');
}
+ $this->tpl->addCss(ilUtil::getStyleSheetLocation("output", "test_print.css", "Modules/Test"), "print");
+ if ($this->object->getShowSolutionAnswersOnly()) {
+ $this->tpl->addCss(ilUtil::getStyleSheetLocation("output", "test_print_hide_content.css", "Modules/Test"), "print");
+ }
+
+ $template = new ilTemplate("tpl.il_as_tst_pass_details_overview_participants.html", true, true, "Modules/Test");
+
+ $this->populateExamId($template, $active_id, (int) $pass);
+ $this->populatePassFinishDate($template, ilObjTest::lookupLastTestPassAccess($active_id, $pass));
+
+
+ $toolbar = $this->buildUserTestResultsToolbarGUI();
if (ilSession::get('tst_results_show_best_solutions')) {
$this->ctrl->setParameter($this, 'hide_best_solutions', '1');
$toolbar->setHideBestSolutionsLinkTarget($this->ctrl->getLinkTarget($this, 'outParticipantsPassDetails'));
@@ -934,37 +905,31 @@ public function outParticipantsPassDetails()
$template->parseCurrentBlock();
}
- $list_of_answers = $this->getPassListOfAnswers($result_array, $active_id, $pass, ilSession::get('tst_results_show_best_solutions'), false, false, false, true, $objectivesList, $testResultHeaderLabelBuilder);
- $template->setVariable("LIST_OF_ANSWERS", $list_of_answers);
- $template->setVariable("PASS_DETAILS", $this->ctrl->getHTML($overviewTableGUI));
-
- $data = $this->object->getCompleteEvaluationData();
- $result = $data->getParticipant($active_id)->getReached() . " " . strtolower($this->lng->txt("of")) . " " . $data->getParticipant($active_id)->getMaxpoints() . " (" . sprintf("%2.2f", $data->getParticipant($active_id)->getReachedPointsInPercent()) . " %" . ")";
- $template->setCurrentBlock('total_score');
- $template->setVariable("TOTAL_RESULT_TEXT", $this->lng->txt('tst_stat_result_resultspoints'));
- $template->setVariable("TOTAL_RESULT", $result);
- $template->parseCurrentBlock();
-
- if (!$this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired()) {
- $template->setVariable("USER_DATA", $user_data);
-
- $uname = $this->object->userLookupFullName($user_id);
- $template->setVariable("TEXT_HEADING", sprintf($this->lng->txt("tst_result_user_name_pass"), $pass + 1, $uname));
+ $title = sprintf(
+ $this->lng->txt("tst_result_user_name_pass"),
+ $pass + 1,
+ ilObjUser::_lookupFullname($this->object->_getUserIdFromActiveId($active_id))
+ );
- $template->setVariable("TEXT_RESULTS", $testResultHeaderLabelBuilder->getPassDetailsHeaderLabel($pass + 1));
- }
+ $pass_results = $this->results_factory->getPassResultsFor(
+ $this->object,
+ $active_id,
+ $pass,
+ false
+ );
- $template->setVariable("FORMACTION", $this->ctrl->getFormAction($this));
+ $table = $this->results_presentation_factory->getPassResultsPresentationTable(
+ $pass_results,
+ $title
+ );
- $this->populateExamId($template, $active_id, $pass);
- $this->populatePassFinishDate($template, ilObjTest::lookupLastTestPassAccess($active_id, $pass));
+ $this->tpl->addCss(ilObjStyleSheet::getContentStylePath(0));
- $this->tpl->addCss(ilUtil::getStyleSheetLocation("output", "test_print.css", "Modules/Test"), "print");
- if ($this->object->getShowSolutionAnswersOnly()) {
- $this->tpl->addCss(ilUtil::getStyleSheetLocation("output", "test_print_hide_content.css", "Modules/Test"), "print");
- }
-
- $this->tpl->setVariable("ADM_CONTENT", $template->get());
+ $this->tpl->setVariable(
+ "ADM_CONTENT",
+ $template->get()
+ . $table->render()
+ );
}
public function outParticipantsResultsOverview()
@@ -1149,14 +1114,10 @@ public function outUserPassDetails(): void
$result_array = $this->getFilteredTestResult($active_id, $pass, $considerHiddenQuestions, $considerOptionalQuestions);
$command_solution_details = "";
- if ($this->object->getShowSolutionDetails()) {
+ if ($this->object->getShowSolutionListComparison()) {
$command_solution_details = "outCorrectSolution";
}
- //$questionAnchorNav = $this->object->canShowSolutionPrintview();
- $questionAnchorNav =
- $this->object->getShowSolutionListOwnAnswers();
-
$tpl = new ilTemplate('tpl.il_as_tst_pass_details_overview_participants.html', true, true, "Modules/Test");
$toolbar = $this->buildUserTestResultsToolbarGUI();
@@ -1191,19 +1152,6 @@ public function outUserPassDetails(): void
$gradingMessageBuilder->sendMessage();
}
- $overviewTableGUI = $this->getPassDetailsOverviewTableGUI(
- $result_array,
- $active_id,
- $pass,
- $this,
- "outUserPassDetails",
- $command_solution_details,
- $questionAnchorNav,
- $objectivesList
- );
- $overviewTableGUI->setTitle($testResultHeaderLabelBuilder->getPassDetailsHeaderLabel($pass + 1));
- $tpl->setVariable("PASS_DETAILS", $this->ctrl->getHTML($overviewTableGUI));
-
$data = $this->object->getCompleteEvaluationData();
$percent = $data->getParticipant($active_id)->getPass($pass)->getReachedPoints() / $data->getParticipant($active_id)->getPass($pass)->getMaxPoints() * 100;
$result = $data->getParticipant($active_id)->getPass($pass)->getReachedPoints() . " " . strtolower($this->lng->txt("of")) . " " . $data->getParticipant($active_id)->getPass($pass)->getMaxPoints() . " (" . sprintf("%2.2f", $percent) . " %" . ")";
@@ -1212,36 +1160,9 @@ public function outUserPassDetails(): void
$tpl->setVariable("TOTAL_RESULT", $result);
$tpl->parseCurrentBlock();
- if ($this->object->getShowSolutionListOwnAnswers()) {
- $list_of_answers = $this->getPassListOfAnswers(
- $result_array,
- $active_id,
- $pass,
- $this->object->getShowSolutionListComparison(),
- false,
- false,
- false,
- true,
- $objectivesList,
- $testResultHeaderLabelBuilder
- );
- $tpl->setVariable("LIST_OF_ANSWERS", $list_of_answers);
- }
-
$tpl->setVariable("TEXT_RESULTS", $testResultHeaderLabelBuilder->getPassDetailsHeaderLabel($pass + 1));
$tpl->setVariable("FORMACTION", $this->ctrl->getFormAction($this));
- $uname = $this->object->userLookupFullName($user_id, true);
- $user_data = $this->getAdditionalUsrDataHtmlAndPopulateWindowTitle($testSession, $active_id, true);
- if (!$this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired()) {
- if ($this->object->getAnonymity()) {
- $tpl->setVariable("TEXT_HEADING", $this->lng->txt("tst_result_pass"));
- } else {
- $tpl->setVariable("TEXT_HEADING", sprintf($this->lng->txt("tst_result_user_name_pass"), $pass + 1, $uname));
- $tpl->setVariable("USER_DATA", $user_data);
- }
- }
-
$this->populateExamId($tpl, $active_id, (int) $pass);
$this->populatePassFinishDate($tpl, ilObjTest::lookupLastTestPassAccess($active_id, $pass));
@@ -1250,7 +1171,31 @@ public function outUserPassDetails(): void
$this->tpl->addCss(ilUtil::getStyleSheetLocation("output", "test_print_hide_content.css", "Modules/Test"), "print");
}
- $this->tpl->setContent($tpl->get());
+ $title = sprintf(
+ $this->lng->txt("tst_result_user_name_pass"),
+ $pass + 1,
+ ilObjUser::_lookupFullname($this->object->_getUserIdFromActiveId($active_id))
+ );
+
+ $pass_results = $this->results_factory->getPassResultsFor(
+ $this->object,
+ $active_id,
+ $pass,
+ true
+ );
+
+ $table = $this->results_presentation_factory->getPassResultsPresentationTable(
+ $pass_results,
+ $title
+ );
+
+ $tpl->setVariable("LIST_OF_ANSWERS", $table->render());
+
+ $this->tpl->addCss(ilObjStyleSheet::getContentStylePath(0));
+
+ $this->tpl->setContent(
+ $tpl->get()
+ );
}
public function outUserResultsOverview()
diff --git a/Modules/Test/classes/class.ilTestNavigationToolbarGUI.php b/Modules/Test/classes/class.ilTestNavigationToolbarGUI.php
index a00c0d445cad..2ea7bf415e02 100644
--- a/Modules/Test/classes/class.ilTestNavigationToolbarGUI.php
+++ b/Modules/Test/classes/class.ilTestNavigationToolbarGUI.php
@@ -28,71 +28,21 @@
*/
class ilTestNavigationToolbarGUI extends ilToolbarGUI
{
- /**
- * @var ilCtrl
- */
- protected $ctrl;
-
- /**
- * @var ilTestPlayerAbstractGUI
- */
- protected $playerGUI;
-
- /**
- * @var bool
- */
- private $suspendTestButtonEnabled = false;
-
- /**
- * @var bool
- */
- private $questionListButtonEnabled = false;
-
- /**
- * @var bool
- */
- private $questionTreeButtonEnabled = false;
-
+ private bool $suspendTestButtonEnabled = false;
private bool $questionTreeVisible = false;
-
- /**
- * @var bool
- */
- private $questionSelectionButtonEnabled = false;
-
- /**
- * @var bool
- */
- private $finishTestButtonEnabled = false;
-
- /**
- * @var string
- */
- private $finishTestCommand = '';
-
- /**
- * @var bool
- */
- private $finishTestButtonPrimary = false;
-
- /**
- * @var bool
- */
- private $disabledStateEnabled = false;
+ private bool $questionSelectionButtonEnabled = false;
+ private bool $finishTestButtonEnabled = false;
+ private string $finishTestCommand = '';
+ private bool $finishTestButtonPrimary = false;
+ private bool $disabledStateEnabled = false;
private bool $user_has_attempts_left = true;
protected ?Interruptive $finish_test_modal = null;
+ protected bool $user_pass_overview_button_enabled = false;
- /**
- * @param ilCtrl $ctrl
- * @param ilLanguage $lng
- * @param ilTestPlayerAbstractGUI $playerGUI
- */
- public function __construct(ilCtrl $ctrl, ilLanguage $lng, ilTestPlayerAbstractGUI $playerGUI)
- {
- $this->ctrl = $ctrl;
- $this->lng = $lng;
- $this->playerGUI = $playerGUI;
-
+ public function __construct(
+ protected ilCtrl $ctrl,
+ protected ilTestPlayerAbstractGUI $playerGUI
+ ) {
parent::__construct();
}
diff --git a/Modules/Test/classes/class.ilTestPasswordChecker.php b/Modules/Test/classes/class.ilTestPasswordChecker.php
index 82a1e7f56269..0eb9d772b1a1 100644
--- a/Modules/Test/classes/class.ilTestPasswordChecker.php
+++ b/Modules/Test/classes/class.ilTestPasswordChecker.php
@@ -56,19 +56,11 @@ public function __construct(ilRbacSystem $rbacsystem, ilObjUser $user, ilObjTest
public function isPasswordProtectionPageRedirectRequired(): bool
{
- if (!$this->isTestPasswordEnabled()) {
- return false;
- }
-
- if ($this->isPrivilegedParticipant()) {
- return false;
- }
-
- if ($this->isUserEnteredPasswordCorrect()) {
- return false;
- }
-
- return true;
+ return (
+ $this->isTestPasswordEnabled()
+ && !$this->isPrivilegedParticipant()
+ && !$this->isUserEnteredPasswordCorrect()
+ );
}
protected function isTestPasswordEnabled(): bool
diff --git a/Modules/Test/classes/class.ilTestPlayerAbstractGUI.php b/Modules/Test/classes/class.ilTestPlayerAbstractGUI.php
index 3242f3a0122f..b8f97de33f0f 100755
--- a/Modules/Test/classes/class.ilTestPlayerAbstractGUI.php
+++ b/Modules/Test/classes/class.ilTestPlayerAbstractGUI.php
@@ -44,6 +44,7 @@ abstract class ilTestPlayerAbstractGUI extends ilTestServiceGUI
public bool $maxProcessingTimeReached;
public bool $endingTimeReached;
+ public int $ref_id;
protected ilTestPasswordChecker $passwordChecker;
protected ilTestProcessLocker $processLocker;
@@ -920,7 +921,7 @@ protected function showQuestionEditable(assQuestionGUI $questionGui, $formAction
$questionNavigationGUI->setDiscardSolutionButtonEnabled(true);
// fau: testNav - set answere status in question header
$questionGui->getQuestionHeaderBlockBuilder()->setQuestionAnswered(true);
- // fau.
+ // fau.
} elseif ($this->object->isPostponingEnabled()) {
$questionNavigationGUI->setSkipQuestionLinkTarget(
$this->ctrl->getLinkTarget($this, ilTestPlayerCommands::SKIP_QUESTION)
@@ -1722,7 +1723,7 @@ protected function populateHelperGuiContent($helperGui)
protected function getTestNavigationToolbarGUI(): ilTestNavigationToolbarGUI
{
- $navigation_toolbar = new ilTestNavigationToolbarGUI($this->ctrl, $this->lng, $this);
+ $navigation_toolbar = new ilTestNavigationToolbarGUI($this->ctrl, $this);
$navigation_toolbar->setSuspendTestButtonEnabled($this->object->getShowCancel());
$navigation_toolbar->setUserPassOverviewEnabled($this->object->getUsrPassOverviewEnabled());
$navigation_toolbar->setFinishTestCommand($this->getFinishTestCommand());
@@ -2167,7 +2168,7 @@ protected function getQuestionGuiInstance($question_id, $fromCache = true): obje
$question_gui->setPresentationContext(assQuestionGUI::PRESENTATION_CONTEXT_TEST);
$question_gui->object->setObligationsToBeConsidered($this->object->areObligationsEnabled());
$question_gui->populateJavascriptFilesRequiredForWorkForm($tpl);
- $question_gui->object->setShuffler($this->buildQuestionAnswerShuffler(
+ $question_gui->object->setShuffler($this->shuffler->getAnswerShuffleFor(
$question_id,
$this->test_session->getActiveId(),
$this->test_session->getPass()
diff --git a/Modules/Test/classes/class.ilTestQuestionNavigationGUI.php b/Modules/Test/classes/class.ilTestQuestionNavigationGUI.php
index edfa7b945a53..ff560c47625e 100644
--- a/Modules/Test/classes/class.ilTestQuestionNavigationGUI.php
+++ b/Modules/Test/classes/class.ilTestQuestionNavigationGUI.php
@@ -444,7 +444,7 @@ public function getHTML(): string
// fau: testNav - skip question (postpone) is moved to the actions menu.
if ($this->getInstantFeedbackCommand()) {
- $this->renderSubmitButton(
+ $this->renderInstantFeedbackButton(
$tpl,
$this->getInstantFeedbackCommand(),
$this->getCheckButtonLabel(),
@@ -601,19 +601,47 @@ private function renderButtonInstance(ilTemplate $tpl, Button $button)
* @param $label
* @param bool|false $primary
*/
- private function renderSubmitButton(ilTemplate $tpl, $command, $label, $primary = false)
- {
- if ($primary) {
- $this->renderButtonInstance(
- $tpl,
- $this->ui_factory->button()->primary($label, $command)
- );
- } else {
+ private function renderSubmitButton(
+ ilTemplate $tpl,
+ string $command,
+ string $label
+ ): void {
+ $this->renderButtonInstance(
+ $tpl,
+ $this->ui_factory->button()->standard($label, $command)
+ );
+ }
+
+ private function renderInstantFeedbackButton(
+ ilTemplate $tpl,
+ string $command,
+ string $label,
+ bool $is_primary
+ ): void {
+ $on_load_code = $this->getOnLoadCode($command);
+ if ($is_primary) {
$this->renderButtonInstance(
$tpl,
- $this->ui_factory->button()->standard($label, $command)
+ $this->ui_factory->button()->primary($label, '')->withAdditionalOnLoadCode($on_load_code)
);
+ return;
}
+
+ $this->renderButtonInstance(
+ $tpl,
+ $this->ui_factory->button()->standard($label, '')->withAdditionalOnLoadCode($on_load_code)
+ );
+ }
+
+ private function getOnLoadCode(string $command): Closure
+ {
+ return static function ($id) use ($command): string {
+ return "document.getElementById('$id').addEventListener('click', "
+ . '(e) => {'
+ . " e.target.setAttribute('name', 'cmd[$command]');"
+ . ' e.target.form.requestSubmit(e.target);'
+ . '});';
+ };
}
/**
diff --git a/Modules/Test/classes/class.ilTestServiceGUI.php b/Modules/Test/classes/class.ilTestServiceGUI.php
index bbe7f8f4616f..3dc21286e285 100755
--- a/Modules/Test/classes/class.ilTestServiceGUI.php
+++ b/Modules/Test/classes/class.ilTestServiceGUI.php
@@ -24,7 +24,6 @@
use ILIAS\GlobalScreen\Services as GlobalScreenServices;
use ILIAS\Refinery\Factory as Refinery;
use ILIAS\Refinery\Transformation;
-use ILIAS\Refinery\Random\Seed\GivenSeed;
use ILIAS\Test\InternalRequestService;
use ILIAS\HTTP\Wrapper\ArrayBasedRequestWrapper;
use ILIAS\DI\LoggingServices;
@@ -78,6 +77,9 @@ class ilTestServiceGUI
protected UIFactory $ui_factory;
protected UIRenderer $ui_renderer;
protected SkillService $skills_service;
+ protected ilTestShuffler $shuffler;
+ protected ilTestResultsFactory $results_factory;
+ protected ilTestResultsPresentationFactory $results_presentation_factory;
protected ILIAS $ilias;
protected ilSetting $settings;
@@ -140,19 +142,26 @@ public function __construct(
$this->rbac_system = $DIC['rbacsystem'];
$this->obj_cache = $DIC['ilObjDataCache'];
$this->skills_service = $DIC->skills();
- $this->participant_access_filter = new ilTestParticipantAccessFilterFactory($DIC['ilAccess']);
$this->post_wrapper = $DIC->http()->wrapper()->post();
- $this->testrequest = $DIC->test()->internal()->request();
+
$this->questioninfo = $DIC->testQuestionPool()->questionInfo();
$this->service = new ilTestService($this->object, $this->db, $this->questioninfo);
- $this->lng->loadLanguageModule('cert');
+ $this->lng->loadLanguageModule('cert');
$this->ref_id = $this->object->getRefId();
- $this->testrequest = $DIC->test()->internal()->request();
$this->testSessionFactory = new ilTestSessionFactory($this->object, $this->db, $this->user);
$this->testSequenceFactory = new ilTestSequenceFactory($this->object, $this->db, $this->questioninfo);
-
$this->objective_oriented_container = null;
+
+ $this->ui_factory = $DIC['ui.factory'];
+ $this->ui_renderer = $DIC['ui.renderer'];
+
+ $local_dic = $object->getLocalDIC();
+ $this->testrequest = $local_dic['request.internal'];
+ $this->participant_access_filter = $local_dic['participantAccessFilterFactory'];
+ $this->shuffler = $local_dic['shuffler'];
+ $this->results_factory = $local_dic['factory.results'];
+ $this->results_presentation_factory = $local_dic['factory.results_presentation'];
}
public function setParticipantData(ilTestParticipantData $participantData): void
@@ -358,7 +367,8 @@ public function getPassListOfAnswers(
&& is_numeric($question_id)) {
$maintemplate->setCurrentBlock("printview_question");
$question_gui = $this->object->createQuestionGUI("", $question_id);
- $question_gui->object->setShuffler($this->buildQuestionAnswerShuffler(
+
+ $question_gui->object->setShuffler($this->shuffler->getAnswerShuffleFor(
(int) $question_id,
(int) $active_id,
(int) $pass
@@ -435,33 +445,6 @@ public function getPassListOfAnswers(
return $maintemplate->get();
}
- protected function buildQuestionAnswerShuffler(
- int $question_id,
- int $active_id,
- int $pass_id
- ): Transformation {
- $fixedSeed = $this->buildFixedShufflerSeed($question_id, $pass_id, $active_id);
-
- return $this->refinery->random()->shuffleArray(new GivenSeed($fixedSeed));
- }
-
- protected function buildFixedShufflerSeed(int $question_id, int $pass_id, int $active_id): int
- {
- $seed = ($question_id + $pass_id) * $active_id;
-
- if (is_float($seed) && is_float($seed = $active_id + $pass_id)) {
- $seed = $active_id;
- }
-
- $div = ceil((10 ** (ilTestPlayerAbstractGUI::FIXED_SHUFFLER_SEED_MIN_LENGTH - 1)) / $seed);
-
- if ($div > 1) {
- $seed = $seed * ($div + $seed % 10);
- }
-
- return (int) $seed;
- }
-
/**
* Returns the list of answers of a users test pass and offers a scoring option
*
@@ -675,7 +658,11 @@ public function getAdditionalUsrDataHtmlAndPopulateWindowTitle($testSession, $ac
$invited_user = array_pop($this->object->getInvitedUsers($user_id));
$title_client = '';
- if (isset($invited_user['clientip']) && $invited_user["clientip"] !== '') {
+ if (is_array($invited_user)
+ && array_key_exists('clientip', $invited_user)
+ && is_string($invited_user['clientip'])
+ && trim($invited_user['clientip']) !== ''
+ ) {
$template->setCurrentBlock("client_ip");
$template->setVariable("TXT_CLIENT_IP", $this->lng->txt("client_ip"));
$template->setVariable("VALUE_CLIENT_IP", $invited_user["clientip"]);
diff --git a/Modules/Test/classes/class.ilTestShuffler.php b/Modules/Test/classes/class.ilTestShuffler.php
new file mode 100644
index 000000000000..d0fef441d634
--- /dev/null
+++ b/Modules/Test/classes/class.ilTestShuffler.php
@@ -0,0 +1,60 @@
+buildFixedShufflerSeed($question_id, $pass_id, $active_id);
+ return $this->refinery->random()->shuffleArray(new GivenSeed($fixedSeed));
+ }
+
+ protected function buildFixedShufflerSeed(int $question_id, int $pass_id, int $active_id): int
+ {
+ $seed = ($question_id + $pass_id) * $active_id;
+ if (is_float($seed) && is_float($seed = $active_id + $pass_id)) {
+ $seed = $active_id;
+ }
+
+ $div = ceil((10 ** (self::FIXED_SHUFFLER_SEED_MIN_LENGTH - 1)) / $seed);
+ if ($div > 1) {
+ $seed = $seed * ($div + $seed % 10);
+ }
+ return (int) $seed;
+ }
+}
diff --git a/Modules/Test/classes/tables/class.ilTestPassOverviewTableGUI.php b/Modules/Test/classes/tables/class.ilTestPassOverviewTableGUI.php
index 275f828c46f8..a63f35c386d3 100644
--- a/Modules/Test/classes/tables/class.ilTestPassOverviewTableGUI.php
+++ b/Modules/Test/classes/tables/class.ilTestPassOverviewTableGUI.php
@@ -18,13 +18,16 @@
declare(strict_types=1);
+use ILIAS\UI\Factory as UIFactory;
+use ILIAS\UI\Renderer as UIRenderer;
+
/**
* Class ilTestPassOverviewTableGUI
*/
class ilTestPassOverviewTableGUI extends ilTable2GUI
{
- private \ILIAS\UI\Factory $ui_factory;
- private \ILIAS\UI\Renderer $ui_renderer;
+ private UIFactory $ui_factory;
+ private UIRenderer $ui_renderer;
protected bool $resultPresentationEnabled = false;
protected bool $pdfPresentationEnabled = false;
@@ -266,12 +269,12 @@ private function buildActionsHtml($actions, $pass): string
}
$this->ctrl->setParameter($this->parent_obj, 'pass', $pass);
- $actions = [];
+ $action_links = [];
if (count($actions) > 1) {
foreach ($actions as $cmd => $label) {
- $actions[] = $this->ui_factory->link()->standard($label, $this->ctrl->getLinkTarget($this->parent_obj, $cmd));
+ $action_links[] = $this->ui_factory->link()->standard($label, $this->ctrl->getLinkTarget($this->parent_obj, $cmd));
}
- $dropdown = $this->ui_factory->dropdown()->standard($actions)->withLabel($this->lng->txt('actions'));
+ $dropdown = $this->ui_factory->dropdown()->standard($action_links)->withLabel($this->lng->txt('actions'));
$html = $this->ui_renderer->render($dropdown);
} else {
$cmd = key($actions);
diff --git a/Modules/Test/classes/toolbars/class.ilTestResultsToolbarGUI.php b/Modules/Test/classes/toolbars/class.ilTestResultsToolbarGUI.php
index 7ce95036e3a6..5c63aa43375b 100644
--- a/Modules/Test/classes/toolbars/class.ilTestResultsToolbarGUI.php
+++ b/Modules/Test/classes/toolbars/class.ilTestResultsToolbarGUI.php
@@ -45,7 +45,9 @@ public function build(): void
{
$this->setId('tst_results_toolbar');
- $this->addButton($this->lng->txt('print'), 'javascript:window.print();');
+ $print_button = $this->ui->factory()->button()->standard($this->lng->txt('print'), '')
+ ->withOnLoadCode(fn($id) => "$('#$id').on('click', ()=>{window.print();})");
+ $this->addComponent($print_button);
if ($this->getCertificateLinkTarget() !== null
&& $this->getCertificateLinkTarget() !== '') {
diff --git a/Modules/Test/templates/default/tpl.il_as_tst_pass_details_overview_participants.html b/Modules/Test/templates/default/tpl.il_as_tst_pass_details_overview_participants.html
index d195f3c6ac2a..1a3108aa34d9 100755
--- a/Modules/Test/templates/default/tpl.il_as_tst_pass_details_overview_participants.html
+++ b/Modules/Test/templates/default/tpl.il_as_tst_pass_details_overview_participants.html
@@ -12,9 +12,10 @@ {TEXT_HEADING}
{TOTAL_RESULT_TEXT}: {TOTAL_RESULT}
-
+
{LIST_OF_ANSWERS}
+
{SIGNATURE}
diff --git a/Modules/Test/test/ScoreSettingsTest.php b/Modules/Test/test/ScoreSettingsTest.php
index 2d69c04a93b2..8bb2d5f274eb 100644
--- a/Modules/Test/test/ScoreSettingsTest.php
+++ b/Modules/Test/test/ScoreSettingsTest.php
@@ -76,13 +76,10 @@ public function testScoreSettingsSummary(): void
public function testScoreSettingsDetails(): void
{
$s = new ilObjTestSettingsResultDetails(-666);
- $this->assertTrue($s->withPrintBestSolutionWithResult(true)->getPrintBestSolutionWithResult());
$this->assertEquals(192, $s->withResultsPresentation(192)->getResultsPresentation(192));
$this->assertTrue($s->withShowExamIdInTestResults(true)->getShowExamIdInTestResults());
$this->assertTrue($s->withShowPassDetails(true)->getShowPassDetails());
$this->assertFalse($s->withShowPassDetails(false)->getShowPassDetails());
- $this->assertTrue($s->withShowSolutionDetails(true)->getShowSolutionDetails());
- $this->assertFalse($s->withShowSolutionDetails(false)->getShowSolutionDetails());
$this->assertTrue($s->withShowSolutionPrintview(true)->getShowSolutionPrintview());
$this->assertFalse($s->withShowSolutionPrintview(false)->getShowSolutionPrintview());
$this->assertTrue($s->withShowSolutionFeedback(true)->getShowSolutionFeedback());
@@ -367,77 +364,55 @@ public function testScoreSettingsSectionDetails(): void
$expected = <<
-