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