ILIAS  release_8 Revision v8.24
class.ilLOTestQuestionAdapter.php
Go to the documentation of this file.
1<?php
18declare(strict_types=0);
19
25{
28 protected array $run = [];
29 protected int $user_id = 0;
30 protected int $container_id = 0;
31 protected ?int $testRefId = null;
32
33 protected ilLogger $logger;
34
35 public function __construct(int $a_user_id, int $a_course_id)
36 {
37 global $DIC;
38
39 $this->logger = $DIC->logger()->crs();
40 $this->user_id = $a_user_id;
41 $this->container_id = $a_course_id;
42 $this->settings = ilLOSettings::getInstanceByObjId($this->container_id);
43 $this->assignments = ilLOTestAssignments::getInstance($this->container_id);
44 }
45
46 public function getTestRefId(): ?int
47 {
48 return $this->testRefId;
49 }
50
51 public function setTestRefId(int $testRefId): void
52 {
53 $this->testRefId = $testRefId;
54 }
55
56 protected function lookupRelevantObjectiveIdsForTest(int $a_container_id, int $a_tst_ref_id, int $a_user_id): array
57 {
59
60 $objective_ids = ilCourseObjective::_getObjectiveIds($a_container_id);
61
62 $relevant_objective_ids = array();
63 if (!$this->getSettings()->hasSeparateInitialTests()) {
64 if ($a_tst_ref_id === $this->getSettings()->getInitialTest()) {
65 $relevant_objective_ids = $objective_ids;
66 }
67 } elseif (!$this->getSettings()->hasSeparateQualifiedTests()) {
68 if ($a_tst_ref_id === $this->getSettings()->getQualifiedTest()) {
69 $relevant_objective_ids = $objective_ids;
70 }
71 }
72
73 foreach ($objective_ids as $objective_id) {
74 $assigned_itest = $assignments->getTestByObjective($objective_id, ilLOSettings::TYPE_TEST_INITIAL);
75 if ($assigned_itest === $a_tst_ref_id) {
76 $relevant_objective_ids[] = $objective_id;
77 }
78 $assigned_qtest = $assignments->getTestByObjective($objective_id, ilLOSettings::TYPE_TEST_QUALIFIED);
79 if ($assigned_qtest === $a_tst_ref_id) {
80 $relevant_objective_ids[] = $objective_id;
81 }
82 }
83
84 $relevant_objective_ids = array_unique($relevant_objective_ids);
85
86 if (count($relevant_objective_ids) <= 1) {
87 return $relevant_objective_ids;
88 }
89
90 // filter passed objectives
91 $test_type = $assignments->getTypeByTest($a_tst_ref_id);
92 $results = new ilLOUserResults($a_container_id, $a_user_id);
93
94 $passed = $results->getCompletedObjectiveIds();
95 $this->logger->debug('Passed objectives are ' . print_r($passed, true) . ' for test type: ' . $test_type);
96
97 // all completed => show all objectives
98 if (count($passed) >= count($relevant_objective_ids)) {
99 return $relevant_objective_ids;
100 }
101
102 $unpassed = array();
103 foreach ($relevant_objective_ids as $objective_id) {
104 if (!in_array($objective_id, $passed)) {
105 $unpassed[] = $objective_id;
106 }
107 }
108 return $unpassed;
109 }
110
114 public function notifyTestStart(ilTestSession $a_test_session, int $a_test_obj_id): void
115 {
116 $relevant_objectives = $this->lookupRelevantObjectiveIdsForTest(
117 $a_test_session->getObjectiveOrientedContainerId(),
118 $a_test_session->getRefId(),
119 $a_test_session->getUserId()
120 );
121 $this->logger->debug('Notify test start: ' . print_r($relevant_objectives, true));
122
123 // delete test runs
125 $a_test_session->getObjectiveOrientedContainerId(),
126 $a_test_session->getUserId(),
127 $a_test_obj_id
128 );
129
130 foreach ($relevant_objectives as $oid) {
131 $this->logger->debug('Adding new run for objective with id: ' . $oid);
132 $run = new ilLOTestRun(
133 $a_test_session->getObjectiveOrientedContainerId(),
134 $a_test_session->getUserId(),
135 $a_test_obj_id,
136 $oid
137 );
138 $run->create();
139 }
140
141 // finally reinitialize test runs
142 $this->initTestRun($a_test_session);
143 }
144
148 public function prepareTestPass(ilTestSession $a_test_session, ilTestSequence $a_test_sequence): bool
149 {
150 $this->logger->debug('Prepare test pass called');
151
152 $this->updateQuestions($a_test_session, $a_test_sequence);
153
154 if ($this->getSettings()->getPassedObjectiveMode() == ilLOSettings::MARK_PASSED_OBJECTIVE_QST) {
155 $this->setQuestionsOptional($a_test_sequence);
156 } elseif ($this->getSettings()->getPassedObjectiveMode() == ilLOSettings::HIDE_PASSED_OBJECTIVE_QST) {
157 $this->hideQuestions($a_test_sequence);
158 }
159
160 $this->storeTestRun();
161 $this->initUserResult($a_test_session);
162
163 // Save test sequence
164 $a_test_sequence->saveToDb();
165
166 return true;
167 }
168
170 ilTestQuestionSequence $a_test_sequence,
171 ilTestQuestionRelatedObjectivesList $a_objectives_list
172 ): void {
173 $testType = $this->assignments->getTypeByTest($this->getTestRefId());
174
175 if ($testType == ilLOSettings::TYPE_TEST_INITIAL && $this->getSettings()->hasSeparateInitialTests()) {
176 $this->buildQuestionRelatedObjectiveListByTest($a_test_sequence, $a_objectives_list);
177 } elseif ($testType == ilLOSettings::TYPE_TEST_QUALIFIED && $this->getSettings()->hasSeparateQualifiedTests()) {
178 $this->buildQuestionRelatedObjectiveListByTest($a_test_sequence, $a_objectives_list);
179 } else {
180 $this->buildQuestionRelatedObjectiveListByQuestions($a_test_sequence, $a_objectives_list);
181 }
182 }
183
185 ilTestQuestionSequence $a_test_sequence,
186 ilTestQuestionRelatedObjectivesList $a_objectives_list
187 ): void {
188 $objectiveIds = array($this->getRelatedObjectivesForSeparatedTest($this->getTestRefId()));
189
190 foreach ($a_test_sequence->getQuestionIds() as $questionId) {
191 $a_objectives_list->addQuestionRelatedObjectives($questionId, $objectiveIds);
192 }
193 }
194
196 ilTestQuestionSequence $a_test_sequence,
197 ilTestQuestionRelatedObjectivesList $a_objectives_list
198 ): void {
199 foreach ($a_test_sequence->getQuestionIds() as $questionId) {
200 if ($a_test_sequence instanceof ilTestRandomQuestionSequence) {
201 $definitionId = $a_test_sequence->getResponsibleSourcePoolDefinitionId($questionId);
202 $objectiveIds = $this->lookupObjectiveIdByRandomQuestionSelectionDefinitionId($definitionId);
203 } else {
204 $objectiveIds = $this->lookupObjectiveIdByFixedQuestionId($questionId);
205 }
206
207 if ($objectiveIds !== []) {
208 $a_objectives_list->addQuestionRelatedObjectives($questionId, $objectiveIds);
209 }
210 }
211 }
212
214 {
215 return ilLORandomTestQuestionPools::lookupObjectiveIdsBySequence($this->getContainerId(), $a_id);
216 }
217
218 protected function lookupObjectiveIdByFixedQuestionId(int $a_question_id): array
219 {
221 }
222
223 protected function getRelatedObjectivesForSeparatedTest(int $testRefId): ?int
224 {
225 foreach ($this->getAssignments()->getAssignments() as $assignment) {
226 if ($assignment->getTestRefId() === $testRefId) {
227 return $assignment->getObjectiveId();
228 }
229 }
230 return null;
231 }
232
233 protected function getUserId(): int
234 {
235 return $this->user_id;
236 }
237
238 protected function getContainerId(): int
239 {
240 return $this->container_id;
241 }
242
243 protected function getSettings(): ilLOSettings
244 {
245 return $this->settings;
246 }
247
249 {
250 return $this->assignments;
251 }
252
253 protected function initUserResult(ilTestSession $session): void
254 {
255 // check if current test is start object and fullfilled
256 // if yes => do not increase tries.
257 $is_qualified_run = false;
258 if ($this->isQualifiedStartRun($session)) {
259 $is_qualified_run = true;
260 }
261
262 foreach ($this->run as $run) {
263 $old_result = ilLOUserResults::lookupResult(
264 $this->container_id,
265 $this->user_id,
266 $run->getObjectiveId(),
267 $this->getAssignments()->getTypeByTest($session->getRefId())
268 );
269
271 $this->container_id,
272 $run->getObjectiveId(),
273 $session->getRefId(),
274 $run->getMaxPoints()
275 );
276
277 $max_attempts = ilLOUtils::lookupMaxAttempts(
278 $this->container_id,
279 $run->getObjectiveId(),
280 $session->getRefId()
281 );
282
283 $this->logger->debug('Max attempts = ' . $max_attempts);
284
285 if ($max_attempts) {
286 // check if current test is start object and fullfilled
287 // if yes => do not increase tries.
288 $this->logger->debug('Checking for qualified test...');
289 if (!$is_qualified_run) {
290 $this->logger->debug(' and increasing attempts.');
291 ++$old_result['tries'];
292 }
293 $old_result['is_final'] = ($old_result['tries'] >= $max_attempts);
294 }
295
296 $ur = new ilLOUserResults($this->container_id, $this->user_id);
297 $ur->saveObjectiveResult(
298 $run->getObjectiveId(),
299 $this->getAssignments()->getTypeByTest($session->getRefId()),
300 $old_result['status'],
301 $old_result['result_perc'],
302 $limit,
303 $old_result['tries'],
304 $old_result['is_final']
305 );
306 }
307 }
308
313 {
314 if ($this->getAssignments()->getTypeByTest($session->getRefId()) == ilLOSettings::TYPE_TEST_INITIAL) {
315 $this->logger->debug('Initial test');
316 return false;
317 }
318
319 if ($session->getRefId() !== $this->getSettings()->getQualifiedTest()) {
320 $this->logger->debug('No qualified test run');
321 return false;
322 }
323 if (!ilContainerStartObjects::isStartObject($this->getContainerId(), $session->getRefId())) {
324 $this->logger->debug('No start object');
325 return false;
326 }
327 // Check if start object is fullfilled
328
329 $container_ref_ids = ilObject::_getAllReferences($this->getContainerId());
330 $container_ref_id = end($container_ref_ids);
331
332 $start = new ilContainerStartObjects(
333 $container_ref_id,
334 $this->getContainerId()
335 );
336 if ($start->isFullfilled($this->getUserId(), $session->getRefId())) {
337 $this->logger->debug('Is fullfilled');
338 return false;
339 }
340 $this->logger->debug('Is not fullfilled');
341 return true;
342 }
343
348 {
349 foreach ($this->run as $run) {
350 if ($run->questionExists($qst->getId())) {
351 $GLOBALS['DIC']['ilLog']->write(__METHOD__ . ': reached points are ' . $qst->getReachedPoints(
352 $session->getActiveId(),
353 $session->getPass()
354 ));
355 $run->setQuestionResult(
356 $qst->getId(),
357 $qst->getReachedPoints($session->getActiveId(), $session->getPass())
358 );
359 $run->update();
360
361 $res = $run->getResult();
362
363 $old_result = ilLOUserResults::lookupResult(
364 $this->container_id,
365 $this->user_id,
366 $run->getObjectiveId(),
367 $this->getAssignments()->getTypeByTest($session->getRefId())
368 );
369
370 $ur = new ilLOUserResults($this->container_id, $this->user_id);
371 $ur->saveObjectiveResult(
372 $run->getObjectiveId(),
373 $this->getAssignments()->getTypeByTest($session->getRefId()),
375 $this->container_id,
376 $session->getRefId(),
377 $run->getObjectiveId(),
378 $res['max'],
379 $res['reached'],
380 $old_result['limit_perc']
381 ) ?
384 (float) $res['percentage'],
385 $old_result['limit_perc'],
386 $old_result['tries'],
387 $old_result['is_final']
388 );
389 ilLPStatusWrapper::_updateStatus($this->container_id, $this->user_id);
390 }
391 }
392 }
393
394 protected function setQuestionsOptional(ilTestSequence $seq): void
395 {
396 // first unset optional on all questions
398 foreach ($seq->getQuestionIds() as $qid) {
399 if (!$this->isInRun($qid)) { // but is assigned to any LO
400 $seq->setQuestionOptional($qid);
401 }
402 }
403 }
404
405 protected function hideQuestions(ilTestSequence $seq): void
406 {
407 // first unhide all questions
408 $seq->clearHiddenQuestions();
409 foreach ($seq->getQuestionIds() as $qid) {
410 if (!$this->isInRun($qid)) {
411 $seq->hideQuestion($qid);
412 }
413 }
414 }
415
416 protected function initTestRun(ilTestSession $session): void
417 {
418 $this->run = ilLOTestRun::getRun(
419 $this->container_id,
420 $this->user_id,
422 );
423 }
424
425 protected function storeTestRun(): void
426 {
427 foreach ($this->run as $tst_run) {
428 $tst_run->update();
429 }
430 }
431
432 protected function updateQuestions(ilTestSession $session, ilTestSequence $seq): void
433 {
434 if ($this->getAssignments()->isSeparateTest($session->getRefId())) {
435 $this->updateSeparateTestQuestions($session, $seq);
436 return;
437 }
438 if ($seq instanceof ilTestSequenceFixedQuestionSet) {
439 $this->updateFixedQuestions($session, $seq);
440 return;
441 }
442 if ($seq instanceof ilTestSequenceRandomQuestionSet) {
443 $this->updateRandomQuestions($session, $seq);
444 }
445 }
446
448 {
449 foreach ($this->run as $tst_run) {
450 $tst_run->clearQuestions();
451 $points = 0;
452 foreach ($seq->getQuestionIds() as $qst_id) {
453 $tst_run->addQuestion($qst_id);
455 }
456 $tst_run->setMaxPoints($points);
457 }
458 }
459
461 {
462 foreach ($this->run as $tst_run) {
463 $tst_run->clearQuestions();
465 ilObject::_lookupObjId($session->getRefId()),
466 $tst_run->getObjectiveId()
467 );
468 $points = 0;
469 foreach ($qst as $id) {
470 $tst_run->addQuestion($id);
472 }
473 $tst_run->setMaxPoints($points);
474 }
475 }
476
478 {
479 foreach ($this->run as $tst_run) {
480 // Clear questions of previous run
481 $tst_run->clearQuestions();
482
484 $this->container_id,
485 $tst_run->getObjectiveId(),
486 ilObject::_lookupObjId($session->getRefId()),
487 (
488 ($this->getSettings()->getQualifiedTest() === $session->getRefId()) ?
491 )
492 );
493
494 $points = 0;
495 foreach ($seq->getQuestionIds() as $qst) {
496 if (in_array($seq->getResponsibleSourcePoolDefinitionId($qst), $sequences)) {
497 $tst_run->addQuestion($qst);
499 }
500 }
501 $tst_run->setMaxPoints($points);
502 }
503 }
504
505 protected function isInRun(int $a_qid): bool
506 {
507 foreach ($this->run as $run) {
508 if ($run->questionExists($a_qid)) {
509 return true;
510 }
511 }
512 return false;
513 }
514
515 public static function getInstance(ilTestSession $a_test_session): self
516 {
517 $adapter = new self(
518 $a_test_session->getUserId(),
519 $a_test_session->getObjectiveOrientedContainerId()
520 );
521
522 $adapter->setTestRefId($a_test_session->getRefId());
523 $adapter->initTestRun($a_test_session);
524 return $adapter;
525 }
526}
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
if(!defined('PATH_SEPARATOR')) $GLOBALS['_PEAR_default_error_mode']
Definition: PEAR.php:64
Abstract basic class which is to be extended by the concrete assessment question type classes.
getReachedPoints(int $active_id, int $pass)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static isStartObject(int $a_container_id, int $a_item_ref_id)
static lookupQuestionsByObjective(int $a_test_id, int $a_objective)
static _lookupMaximumPointsOfQuestion(int $a_question_id)
static _getObjectiveIds(int $course_id, bool $a_activated_only=false)
static lookupObjectiveIdsBySequence(int $a_container_id, int $a_seq_id)
static lookupSequencesByType(int $a_container_id, int $a_objective_id, int $a_test_id, int $a_test_type)
Settings for LO courses.
static getInstanceByObjId(int $a_obj_id)
const HIDE_PASSED_OBJECTIVE_QST
const MARK_PASSED_OBJECTIVE_QST
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
getTestByObjective(int $a_objective_id, int $a_type)
getTypeByTest(int $a_test_ref_id)
static getInstance(int $a_container_id)
notifyTestStart(ilTestSession $a_test_session, int $a_test_obj_id)
Called from learning objective test on actual test start.
isQualifiedStartRun(ilTestSession $session)
Check if current run is a start object run.
buildQuestionRelatedObjectiveListByQuestions(ilTestQuestionSequence $a_test_sequence, ilTestQuestionRelatedObjectivesList $a_objectives_list)
buildQuestionRelatedObjectiveListByTest(ilTestQuestionSequence $a_test_sequence, ilTestQuestionRelatedObjectivesList $a_objectives_list)
prepareTestPass(ilTestSession $a_test_session, ilTestSequence $a_test_sequence)
Called from learning objective test.
buildQuestionRelatedObjectiveList(ilTestQuestionSequence $a_test_sequence, ilTestQuestionRelatedObjectivesList $a_objectives_list)
__construct(int $a_user_id, int $a_course_id)
lookupObjectiveIdByFixedQuestionId(int $a_question_id)
updateQuestions(ilTestSession $session, ilTestSequence $seq)
updateQuestionResult(ilTestSession $session, assQuestion $qst)
update question result of run
updateSeparateTestQuestions(ilTestSession $session, ilTestSequence $seq)
updateRandomQuestions(ilTestSession $session, ilTestSequenceRandomQuestionSet $seq)
lookupObjectiveIdByRandomQuestionSelectionDefinitionId(int $a_id)
initUserResult(ilTestSession $session)
lookupRelevantObjectiveIdsForTest(int $a_container_id, int $a_tst_ref_id, int $a_user_id)
static getInstance(ilTestSession $a_test_session)
updateFixedQuestions(ilTestSession $session, ilTestSequence $seq)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static deleteRun(int $a_container_id, int $a_user_id, int $a_test_id)
static getRun(int $a_container_id, int $a_user_id, int $a_test_id)
static lookupResult(int $a_course_obj_id, int $a_user_id, int $a_objective_id, int $a_tst_type)
static lookupObjectiveRequiredPercentage(int $a_container_id, int $a_objective_id, int $a_test_ref_id, int $a_max_points)
static isCompleted(int $a_cont_oid, int $a_test_rid, int $a_objective_id, int $max_points, int $reached, int $limit_perc)
Check if objective is completed.
static lookupMaxAttempts(int $a_container_id, int $a_objective_id, int $a_test_ref_id)
static _updateStatus(int $a_obj_id, int $a_usr_id, ?object $a_obj=null, bool $a_percentage=false, bool $a_force_raise=false)
Component logger with individual log levels by component id.
static _getAllReferences(int $id)
get all reference ids for object ID
static _lookupObjId(int $ref_id)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
hideQuestion($question_id)
saveToDb()
Saves the sequence data for a given pass to the database.
setQuestionOptional($questionId)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
global $DIC
Definition: feed.php:28
$res
Definition: ltiservices.php:69
array $settings
Setting values (LTI parameters, custom parameters and local parameters).
Definition: System.php:200
$session
$results