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