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