ILIAS  release_8 Revision v8.19
All Data Structures Namespaces Files Functions Variables Modules Pages
class.ilTestSequenceDynamicQuestionSet.php
Go to the documentation of this file.
1 <?php
2 
30 {
34  private $db = null;
35 
39  private $questionSet = null;
40 
44  private $activeId = null;
45 
50 
54  private $questionTracking = array();
55 
60 
65 
69  private $postponedQuestions = array();
70 
75 
80 
85 
90 
94  private $correctAnsweredQuestions = array();
95 
99  private $wrongAnsweredQuestions = array();
100 
105 
110 
115 
122  {
123  $this->db = $db;
124  $this->questionSet = $questionSet;
125  $this->activeId = $activeId;
126 
127  $this->newlyTrackedQuestion = null;
128  $this->newlyTrackedQuestionsStatus = null;
129 
130  $this->newlyPostponedQuestion = null;
131  $this->newlyPostponedQuestionsCount = null;
132 
133  $this->newlyAnsweredQuestion = null;
134  $this->newlyAnsweredQuestionsAnswerStatus = null;
135 
136  $this->alreadyCheckedQuestions = array();
137  $this->newlyCheckedQuestion = null;
138 
139  $this->preventCheckedQuestionsFromComingUpEnabled = false;
140 
141  $this->currentQuestionId = null;
142  }
143 
144  public function getActiveId(): ?int
145  {
146  return $this->activeId;
147  }
148 
150  {
151  $this->preventCheckedQuestionsFromComingUpEnabled = $preventCheckedQuestionsFromComingUpEnabled;
152  }
153 
155  {
157  }
158 
162  public function getCurrentQuestionId(): ?int
163  {
165  }
166 
171  {
172  $this->currentQuestionId = $currentQuestionId;
173  }
174 
175  public function loadFromDb()
176  {
177  $this->loadQuestionTracking();
178  $this->loadAnswerStatus();
179  $this->loadPostponedQuestions();
180  $this->loadCheckedQuestions();
181  }
182 
183  private function loadQuestionTracking()
184  {
185  $query = "
186  SELECT question_fi, status
187  FROM tst_seq_qst_tracking
188  WHERE active_fi = %s
189  AND pass = %s
190  ORDER BY orderindex ASC
191  ";
192 
193  $res = $this->db->queryF($query, array('integer','integer'), array($this->activeId, 0));
194 
195  $this->questionTracking = array();
196 
197  while ($row = $this->db->fetchAssoc($res)) {
198  $this->questionTracking[] = array(
199  'qid' => $row['question_fi'],
200  'status' => $row['status']
201  );
202  }
203  }
204 
205  private function loadAnswerStatus()
206  {
207  $query = "
208  SELECT question_fi, correctness
209  FROM tst_seq_qst_answstatus
210  WHERE active_fi = %s
211  AND pass = %s
212  ";
213 
214  $res = $this->db->queryF($query, array('integer','integer'), array($this->activeId, 0));
215 
216  $this->correctAnsweredQuestions = array();
217  $this->wrongAnsweredQuestions = array();
218 
219  while ($row = $this->db->fetchAssoc($res)) {
220  if ($row['correctness']) {
221  $this->correctAnsweredQuestions[ $row['question_fi'] ] = $row['question_fi'];
222  } else {
223  $this->wrongAnsweredQuestions[ $row['question_fi'] ] = $row['question_fi'];
224  }
225  }
226  }
227 
228  private function loadPostponedQuestions()
229  {
230  $query = "
231  SELECT question_fi, cnt
232  FROM tst_seq_qst_postponed
233  WHERE active_fi = %s
234  AND pass = %s
235  ";
236 
237  $res = $this->db->queryF($query, array('integer','integer'), array($this->activeId, 0));
238 
239  $this->postponedQuestions = array();
240 
241  while ($row = $this->db->fetchAssoc($res)) {
242  $this->postponedQuestions[ $row['question_fi'] ] = $row['cnt'];
243  }
244  }
245 
246  private function loadCheckedQuestions()
247  {
248  $res = $this->db->queryF(
249  "SELECT question_fi FROM tst_seq_qst_checked WHERE active_fi = %s AND pass = %s",
250  array('integer','integer'),
251  array($this->getActiveId(), 0)
252  );
253 
254  while ($row = $this->db->fetchAssoc($res)) {
255  $this->alreadyCheckedQuestions[ $row['question_fi'] ] = $row['question_fi'];
256  }
257  }
258 
259  public function saveToDb()
260  {
261  $this->db->manipulateF(
262  "DELETE FROM tst_sequence WHERE active_fi = %s AND pass = %s",
263  array('integer','integer'),
264  array($this->getActiveId(), 0)
265  );
266 
267  $this->db->insert('tst_sequence', array(
268  'active_fi' => array('integer', $this->getActiveId()),
269  'pass' => array('integer', 0),
270  'sequence' => array('clob', null),
271  'postponed' => array('text', null),
272  'hidden' => array('text', null),
273  'tstamp' => array('integer', time())
274  ));
275 
276  $this->saveNewlyTrackedQuestion();
280  $this->saveNewlyCheckedQuestion();
282  }
283 
284  private function saveNewlyTrackedQuestion()
285  {
286  if ((int) $this->newlyTrackedQuestion) {
287  $newOrderIndex = $this->getNewOrderIndexForQuestionTracking();
288 
289  $this->db->replace(
290  'tst_seq_qst_tracking',
291  array(
292  'active_fi' => array('integer', (int) $this->getActiveId()),
293  'pass' => array('integer', 0),
294  'question_fi' => array('integer', (int) $this->newlyTrackedQuestion)
295  ),
296  array(
297  'status' => array('text', $this->newlyTrackedQuestionsStatus),
298  'orderindex' => array('integer', $newOrderIndex)
299  )
300  );
301  }
302  }
303 
305  {
306  $query = "
307  SELECT (MAX(orderindex) + 1) new_order_index
308  FROM tst_seq_qst_tracking
309  WHERE active_fi = %s
310  AND pass = %s
311  ";
312 
313  $res = $this->db->queryF($query, array('integer','integer'), array($this->getActiveId(), 0));
314 
315  $row = $this->db->fetchAssoc($res);
316 
317  if ($row['new_order_index']) {
318  return $row['new_order_index'];
319  }
320 
321  return 1;
322  }
323 
325  {
326  if ((int) $this->newlyAnsweredQuestion) {
327  $this->db->replace(
328  'tst_seq_qst_answstatus',
329  array(
330  'active_fi' => array('integer', (int) $this->getActiveId()),
331  'pass' => array('integer', 0),
332  'question_fi' => array('integer', (int) $this->newlyAnsweredQuestion)
333  ),
334  array(
335  'correctness' => array('integer', (int) $this->newlyAnsweredQuestionsAnswerStatus)
336  )
337  );
338  }
339  }
340 
341  private function saveNewlyPostponedQuestion()
342  {
343  if ((int) $this->newlyPostponedQuestion) {
344  $this->db->replace(
345  'tst_seq_qst_postponed',
346  array(
347  'active_fi' => array('integer', (int) $this->getActiveId()),
348  'pass' => array('integer', 0),
349  'question_fi' => array('integer', (int) $this->newlyPostponedQuestion)
350  ),
351  array(
352  'cnt' => array('integer', (int) $this->newlyPostponedQuestionsCount)
353  )
354  );
355  }
356  }
357 
359  {
360  $INquestions = $this->db->in('question_fi', array_keys($this->postponedQuestions), true, 'integer');
361 
362  $query = "
363  DELETE FROM tst_seq_qst_postponed
364  WHERE active_fi = %s
365  AND pass = %s
366  AND $INquestions
367  ";
368 
369  $this->db->manipulateF($query, array('integer','integer'), array($this->getActiveId(), 0));
370  }
371 
372  private function saveNewlyCheckedQuestion()
373  {
374  if ((int) $this->newlyCheckedQuestion) {
375  $this->db->replace('tst_seq_qst_checked', array(
376  'active_fi' => array('integer', (int) $this->getActiveId()),
377  'pass' => array('integer', 0),
378  'question_fi' => array('integer', (int) $this->newlyCheckedQuestion)
379  ), array());
380  }
381  }
382 
384  {
385  $NOT_IN_checkedQuestions = $this->db->in('question_fi', $this->alreadyCheckedQuestions, true, 'integer');
386 
387  // BEGIN: FIX IN QUERY
388  if ($NOT_IN_checkedQuestions == ' 1=2 ') {
389  $NOT_IN_checkedQuestions = ' 1=1 ';
390  }
391  // END: FIX IN QUERY
392 
393  $query = "
394  DELETE FROM tst_seq_qst_checked
395  WHERE active_fi = %s
396  AND pass = %s
397  AND $NOT_IN_checkedQuestions
398  ";
399 
400  $this->db->manipulateF($query, array('integer', 'integer'), array((int) $this->getActiveId(), 0));
401  }
402 
403  public function loadQuestions(ilObjTestDynamicQuestionSetConfig $dynamicQuestionSetConfig, ilTestDynamicQuestionSetFilterSelection $filterSelection)
404  {
405  $this->questionSet->load($dynamicQuestionSetConfig, $filterSelection);
406 
407  // echo "<table><tr>";
408 // echo "<td width='200'><pre>".print_r($this->questionSet->getActualQuestionSequence(), 1)."</pre></td>";
409 // echo "<td width='200'><pre>".print_r($this->correctAnsweredQuestions, 1)."</pre></td>";
410 // echo "<td width='200'><pre>".print_r($this->wrongAnsweredQuestions, 1)."</pre></td>";
411 // echo "</tr></table>";
412  }
413 
414  // -----------------------------------------------------------------------------------------------------------------
415 
416  public function cleanupQuestions(ilTestSessionDynamicQuestionSet $testSession)
417  {
418  switch (true) {
419  case !$this->questionSet->questionExists($testSession->getCurrentQuestionId()):
420  case !$this->isFilteredQuestion($testSession->getCurrentQuestionId()):
421 
422  $testSession->setCurrentQuestionId(null);
423  }
424 
425  foreach ($this->postponedQuestions as $questionId) {
426  if (!$this->questionSet->questionExists($questionId)) {
427  unset($this->postponedQuestions[$questionId]);
428  }
429  }
430 
431  foreach ($this->wrongAnsweredQuestions as $questionId) {
432  if (!$this->questionSet->questionExists($questionId)) {
433  unset($this->wrongAnsweredQuestions[$questionId]);
434  }
435  }
436 
437  foreach ($this->correctAnsweredQuestions as $questionId) {
438  if (!$this->questionSet->questionExists($questionId)) {
439  unset($this->correctAnsweredQuestions[$questionId]);
440  }
441  }
442  }
443 
444  // -----------------------------------------------------------------------------------------------------------------
445 
446  public function getUpcomingQuestionId()
447  {
448  if ($questionId = $this->fetchUpcomingQuestionId(true, true)) {
449  return $questionId;
450  }
451 
452  if ($questionId = $this->fetchUpcomingQuestionId(false, true)) {
453  return $questionId;
454  }
455 
456  if ($questionId = $this->fetchUpcomingQuestionId(true, false)) {
457  return $questionId;
458  }
459 
460  if ($questionId = $this->fetchUpcomingQuestionId(false, false)) {
461  return $questionId;
462  }
463 
464  return null;
465  }
466 
467  private function fetchUpcomingQuestionId($excludePostponedQuestions, $forceNonAnsweredQuestion)
468  {
469  foreach ($this->questionSet->getActualQuestionSequence() as $level => $questions) {
470  $postponedQuestions = array();
471 
472  foreach ($questions as $pos => $qId) {
473  if (isset($this->correctAnsweredQuestions[$qId])) {
474  continue;
475  }
476 
478  continue;
479  }
480 
481  if ($forceNonAnsweredQuestion && isset($this->wrongAnsweredQuestions[$qId])) {
482  continue;
483  }
484 
485  if (isset($this->postponedQuestions[$qId])) {
486  $postponedQuestions[$qId] = $this->postponedQuestions[$qId];
487  continue;
488  }
489 
490  return $qId;
491  }
492 
493  if (!$excludePostponedQuestions && count($postponedQuestions)) {
495  }
496  }
497 
498  return null;
499  }
500 
501  public function isAnsweredQuestion($questionId): bool
502  {
503  return (
504  isset($this->correctAnsweredQuestions[$questionId])
505  || isset($this->wrongAnsweredQuestions[$questionId])
506  );
507  }
508 
509  public function isPostponedQuestion($questionId): bool
510  {
511  return isset($this->postponedQuestions[$questionId]);
512  }
513 
514  public function isFilteredQuestion($questionId): bool
515  {
516  foreach ($this->questionSet->getActualQuestionSequence() as $level => $questions) {
517  if (in_array($questionId, $questions)) {
518  return true;
519  }
520  }
521 
522  return false;
523  }
524 
525  public function trackedQuestionExists(): bool
526  {
527  return (bool) count($this->questionTracking);
528  }
529 
530  public function getTrackedQuestionList($currentQuestionId = null): array
531  {
532  $questionList = array();
533 
534  if ($currentQuestionId) {
535  $questionList[$currentQuestionId] = $this->questionSet->getQuestionData($currentQuestionId);
536  }
537 
538  foreach (array_reverse($this->questionTracking) as $trackedQuestion) {
539  if (!isset($questionList[ $trackedQuestion['qid'] ])) {
540  $questionList[ $trackedQuestion['qid'] ] = $this->questionSet->getQuestionData($trackedQuestion['qid']);
541  }
542  }
543 
544  return $questionList;
545  }
546 
547  public function resetTrackedQuestionList()
548  {
549  $this->questionTracking = array();
550  }
551 
552  public function openQuestionExists(): bool
553  {
554  return count($this->getOpenQuestions()) > 0;
555  }
556 
557  public function getOpenQuestions(): array
558  {
559  $completeQuestionIds = array_keys($this->questionSet->getAllQuestionsData());
560 
561  $openQuestions = array_diff($completeQuestionIds, $this->correctAnsweredQuestions);
562 
563  return $openQuestions;
564  }
565 
566  public function getTrackedQuestionCount(): int
567  {
568  $uniqueQuestions = array();
569 
570  foreach ($this->questionTracking as $trackedQuestion) {
571  $uniqueQuestions[$trackedQuestion['qid']] = $trackedQuestion['qid'];
572  }
573 
574  return count($uniqueQuestions);
575  }
576 
577  public function getCurrentPositionIndex($questionId): ?int
578  {
579  $i = 0;
580 
581  foreach ($this->getSelectionOrderedSequence() as $qId) {
582  $i++;
583 
584  if ($qId == $questionId) {
585  return $i;
586  }
587  }
588 
589  return null;
590  }
591 
592  public function getLastPositionIndex(): int
593  {
594  return count($this->getSelectionOrderedSequence());
595  }
596 
597  // -----------------------------------------------------------------------------------------------------------------
598 
599  public function setQuestionUnchecked($questionId)
600  {
601  unset($this->alreadyCheckedQuestions[$questionId]);
602  }
603 
604  public function setQuestionChecked($questionId)
605  {
606  $this->newlyCheckedQuestion = $questionId;
607  $this->alreadyCheckedQuestions[$questionId] = $questionId;
608  }
609 
610  public function isQuestionChecked($questionId): bool
611  {
612  return isset($this->alreadyCheckedQuestions[$questionId]);
613  }
614 
615  public function setQuestionPostponed($questionId)
616  {
617  $this->trackQuestion($questionId, 'postponed');
618 
619  if (!isset($this->postponedQuestions[$questionId])) {
620  $this->postponedQuestions[$questionId] = 0;
621  }
622 
623  $this->postponedQuestions[$questionId]++;
624 
625  $this->newlyPostponedQuestion = $questionId;
626  $this->newlyPostponedQuestionsCount = $this->postponedQuestions[$questionId];
627  }
628 
629  public function unsetQuestionPostponed($questionId)
630  {
631  if (isset($this->postponedQuestions[$questionId])) {
632  unset($this->postponedQuestions[$questionId]);
633  }
634  }
635 
636  public function setQuestionAnsweredCorrect($questionId)
637  {
638  $this->trackQuestion($questionId, 'correct');
639 
640  $this->correctAnsweredQuestions[$questionId] = $questionId;
641 
642  if (isset($this->wrongAnsweredQuestions[$questionId])) {
643  unset($this->wrongAnsweredQuestions[$questionId]);
644  }
645 
646  $this->newlyAnsweredQuestion = $questionId;
647  $this->newlyAnsweredQuestionsAnswerStatus = true;
648  }
649 
650  public function setQuestionAnsweredWrong($questionId)
651  {
652  $this->trackQuestion($questionId, 'wrong');
653 
654  $this->wrongAnsweredQuestions[$questionId] = $questionId;
655 
656  if (isset($this->correctAnsweredQuestions[$questionId])) {
657  unset($this->correctAnsweredQuestions[$questionId]);
658  }
659 
660  $this->newlyAnsweredQuestion = $questionId;
661  $this->newlyAnsweredQuestionsAnswerStatus = false;
662  }
663 
664  private function trackQuestion($questionId, $answerStatus)
665  {
666  $this->questionTracking[] = array(
667  'qid' => $questionId, 'status' => $answerStatus
668  );
669 
670  $this->newlyTrackedQuestion = $questionId;
671  $this->newlyTrackedQuestionsStatus = $answerStatus;
672  }
673 
674  // -----------------------------------------------------------------------------------------------------------------
675 
676  public function hasStarted(): bool
677  {
678  return $this->trackedQuestionExists();
679  }
680 
681  // -----------------------------------------------------------------------------------------------------------------
682 
687  {
688  return $this->questionSet;
689  }
690 
691  public function getCompleteQuestionsData(): array
692  {
693  return $this->questionSet->getCompleteQuestionList()->getQuestionDataArray();
694  }
695 
696  public function getFilteredQuestionsData(): array
697  {
698  return $this->questionSet->getFilteredQuestionList()->getQuestionDataArray();
699  }
700 
701  // -----------------------------------------------------------------------------------------------------------------
702 
703  public function getUserSequenceQuestions(): array
704  {
705  //return array_keys( $this->getTrackedQuestionList() );
706 
707  $questionSequence = array();
708 
709  foreach ($this->questionSet->getActualQuestionSequence() as $level => $questions) {
710  $questionSequence = array_merge($questionSequence, $questions);
711  }
712 
713  return $questionSequence;
714  }
715 
721  {
722  $minPostponeCount = null;
723  $minPostponeItem = null;
724 
725  foreach (array_reverse($postponedQuestions, true) as $qId => $postponeCount) {
726  if ($minPostponeCount === null || $postponeCount <= $minPostponeCount) {
727  $minPostponeCount = $postponeCount;
728  $minPostponeItem = $qId;
729  }
730  }
731  return $minPostponeItem;
732  }
733 
734  public function getPass(): int
735  {
736  return 0;
737  }
738 
739  // -----------------------------------------------------------------------------------------------------------------
740 
742  {
743  $maxPostponeCount = max($postponedQuestions);
744 
745  $orderedSequence = array();
746  $postponedCountDomain = array_flip($postponedQuestions);
747 
748  for ($i = 1; $i <= $maxPostponeCount; $i++) {
749  if (!isset($postponedCountDomain[$i])) {
750  continue;
751  }
752 
753  foreach ($postponedQuestions as $qId => $postponeCount) {
754  if ($postponeCount == $i) {
755  $orderedSequence[] = $qId;
756  }
757  }
758  }
759 
760  return $orderedSequence;
761  }
762 
763  private function fetchQuestionSequence($nonPostponedQuestions, $nonAnsweredQuestions): array
764  {
765  $questionSequence = array();
766 
767  foreach ($this->questionSet->getActualQuestionSequence() as $level => $questions) {
768  $postponedQuestions = array();
769 
770  foreach ($questions as $pos => $qId) {
771  if (isset($this->correctAnsweredQuestions[$qId])) {
772  continue;
773  }
774 
775  if ($nonAnsweredQuestions && isset($this->wrongAnsweredQuestions[$qId])) {
776  continue;
777  } elseif (!$nonAnsweredQuestions && !isset($this->wrongAnsweredQuestions[$qId])) {
778  continue;
779  }
780 
781  if (!$nonPostponedQuestions && isset($this->postponedQuestions[$qId])) {
782  $postponedQuestions[$qId] = $this->postponedQuestions[$qId];
783  continue;
784  } elseif ($nonPostponedQuestions && !isset($this->postponedQuestions[$qId])) {
785  $questionSequence[] = $qId;
786  }
787  }
788 
789  if (!$nonPostponedQuestions && count($postponedQuestions)) {
790  $questionSequence = array_merge(
791  $questionSequence,
793  );
794  }
795  }
796 
797  return $questionSequence;
798  }
799 
800  private function fetchTrackedCorrectAnsweredSequence(): array
801  {
802  $questionSequence = array();
803 
804  foreach ($this->questionTracking as $key => $question) {
805  $qId = $question['qid'];
806 
807  if (!isset($this->correctAnsweredQuestions[$qId])) {
808  continue;
809  }
810 
811  $questionSequence[] = $qId;
812  }
813 
814  return $questionSequence;
815  }
816 
817  private function getOrderedSequence(): array
818  {
820 
821  $nonAnsweredQuestions = $this->fetchQuestionSequence(
822  true,
823  true
824  );
825 
826  $postponedNonAnsweredQuestions = $this->fetchQuestionSequence(
827  false,
828  true
829  );
830 
832  true,
833  false
834  );
835 
836  $postponedWrongAnsweredQuestions = $this->fetchQuestionSequence(
837  false,
838  false
839  );
840 
841  $questionOrder = array_merge(
843  $nonAnsweredQuestions,
844  $postponedNonAnsweredQuestions,
846  $postponedWrongAnsweredQuestions
847  );
848 
849  return $questionOrder;
850  }
851 
852  public function getSelectionOrderedSequence(): array
853  {
854  $sequence = array();
855 
856  foreach ($this->getOrderedSequence() as $qId) {
857  if (!$this->getQuestionSet()->getSelectionQuestionList()->isInList($qId)) {
858  continue;
859  }
860 
861  $sequence[] = $qId;
862  }
863 
864  return $sequence;
865  }
866 
867  public function getSequenceSummary($obligationsFilterEnabled = false): array
868  {
869  $questionOrder = $this->getSelectionOrderedSequence();
870 
871  $solved_questions = ilObjTest::_getSolvedQuestions($this->getActiveId());
872 
873  $key = 1;
874 
875  $summary = array();
876 
877  foreach ($questionOrder as $qId) {
878  $question = ilObjTest::_instanciateQuestion($qId);
879  if (is_object($question)) {
880  $worked_through = $question->_isWorkedThrough($this->getActiveId(), $question->getId(), $this->getPass());
881  $solved = 0;
882  if (array_key_exists($question->getId(), $solved_questions)) {
883  $solved = $solved_questions[$question->getId()]["solved"];
884  }
885 
886  // do not show postponing, since this happens implicit on dircarding solutions (CTM only)
887  //$is_postponed = $this->isPostponedQuestion($question->getId());
888 
889  $row = array("nr" => "$key", "title" => $question->getTitle(), "qid" => $question->getId(), "visited" => $worked_through, "solved" => (($solved) ? "1" : "0"), "description" => $question->getComment(), "points" => $question->getMaximumPoints(), "worked_through" => $worked_through, "postponed" => false, "sequence" => $qId, "obligatory" => ilObjTest::isQuestionObligatory($question->getId()), 'isAnswered' => $question->isAnswered($this->getActiveId(), $this->getPass()));
890 
891  if (!$obligationsFilterEnabled || $row['obligatory']) {
892  $summary[] = $row;
893  }
894 
895  $key++;
896  }
897  }
898 
899  return $summary;
900  }
901 
903  {
904  $filteredQuestions = $this->questionSet->getFilteredQuestionList()->getQuestionDataArray();
905 
906  foreach ($filteredQuestions as $filteredQuestion) {
907  if ($this->isQuestionChecked($filteredQuestion['question_id'])) {
908  return true;
909  }
910  }
911 
912  return false;
913  }
914 
916  {
917  $filteredQuestions = $this->questionSet->getFilteredQuestionList()->getQuestionDataArray();
918 
919  foreach ($filteredQuestions as $filteredQuestion) {
920  if ($this->isQuestionChecked($filteredQuestion['question_id'])) {
921  $this->setQuestionUnchecked($filteredQuestion['question_id']);
922  }
923  }
924  }
925 }
$res
Definition: ltiservices.php:69
setPreventCheckedQuestionsFromComingUpEnabled($preventCheckedQuestionsFromComingUpEnabled)
cleanupQuestions(ilTestSessionDynamicQuestionSet $testSession)
loadQuestions(ilObjTestDynamicQuestionSetConfig $dynamicQuestionSetConfig, ilTestDynamicQuestionSetFilterSelection $filterSelection)
static _instanciateQuestion($question_id)
Creates an instance of a question with a given question id.
static isQuestionObligatory($question_id)
checks wether the question with given id is marked as obligatory or not
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static _getSolvedQuestions($active_id, $question_fi=null)
get solved questions
string $key
Consumer key/client ID value.
Definition: System.php:193
$query
__construct(ilDBInterface $db, ilTestDynamicQuestionSet $questionSet, $activeId)
Constructor.
fetchQuestionSequence($nonPostponedQuestions, $nonAnsweredQuestions)
fetchUpcomingQuestionId($excludePostponedQuestions, $forceNonAnsweredQuestion)
$i
Definition: metadata.php:41