ILIAS  release_5-0 Revision 5.0.0-1144-gc4397b1f870
class.ilTestSequence.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
3
14{
21
28
35
41 var $pass;
42
49
54
59
69 function ilTestSequence($active_id, $pass, $randomtest)
70 {
71 $this->active_id = $active_id;
72 $this->pass = $pass;
73 $this->isRandomTest = $randomtest;
74 $this->sequencedata = array(
75 "sequence" => array(),
76 "postponed" => array(),
77 "hidden" => array()
78 );
79
80 $this->alreadyCheckedQuestions = array();
81 $this->newlyCheckedQuestion = null;
82 }
83
84 function getActiveId()
85 {
86 return $this->active_id;
87 }
88
89 function createNewSequence($max, $shuffle)
90 {
91 $newsequence = array();
92 if ($max > 0)
93 {
94 for ($i = 1; $i <= $max; $i++)
95 {
96 array_push($newsequence, $i);
97 }
98 if ($shuffle) $newsequence = $this->pcArrayShuffle($newsequence);
99 }
100 $this->sequencedata["sequence"] = $newsequence;
101 }
102
106 public function loadQuestions(ilTestQuestionSetConfig $testQuestionSetConfig = null, $taxonomyFilterSelection = array())
107 {
108 global $ilDB;
109
110 $this->questions = array();
111
112 $result = $ilDB->queryF("SELECT tst_test_question.* FROM tst_test_question, qpl_questions, tst_active WHERE tst_active.active_id = %s AND tst_test_question.test_fi = tst_active.test_fi AND qpl_questions.question_id = tst_test_question.question_fi ORDER BY tst_test_question.sequence",
113 array('integer'),
114 array($this->active_id)
115 );
116
117 $index = 1;
118
119 while ($data = $ilDB->fetchAssoc($result))
120 {
121 $this->questions[$index++] = $data["question_fi"];
122 }
123 }
124
130 public function loadFromDb()
131 {
132 $this->loadQuestionSequence();
133 $this->loadCheckedQuestions();
134 }
135
136 private function loadQuestionSequence()
137 {
138 global $ilDB;
139 $result = $ilDB->queryF("SELECT * FROM tst_sequence WHERE active_fi = %s AND pass = %s",
140 array('integer','integer'),
141 array($this->active_id, $this->pass)
142 );
143 if ($result->numRows())
144 {
145 $row = $ilDB->fetchAssoc($result);
146 $this->sequencedata = array(
147 "sequence" => unserialize($row["sequence"]),
148 "postponed" => unserialize($row["postponed"]),
149 "hidden" => unserialize($row["hidden"])
150 );
151 if (!is_array($this->sequencedata["sequence"])) $this->sequencedata["sequence"] = array();
152 if (!is_array($this->sequencedata["postponed"])) $this->sequencedata["postponed"] = array();
153 if (!is_array($this->sequencedata["hidden"])) $this->sequencedata["hidden"] = array();
154 }
155 }
156
157 private function loadCheckedQuestions()
158 {
159 global $ilDB;
160
161 $res = $ilDB->queryF("SELECT question_fi FROM tst_seq_qst_checked WHERE active_fi = %s AND pass = %s",
162 array('integer','integer'), array($this->active_id, $this->pass)
163 );
164
165 while( $row = $ilDB->fetchAssoc($res) )
166 {
167 $this->alreadyCheckedQuestions[ $row['question_fi'] ] = $row['question_fi'];
168 }
169 }
170
176 public function saveToDb()
177 {
178 $this->saveQuestionSequence();
180 }
181
182 private function saveQuestionSequence()
183 {
184 global $ilDB;
185
186 $postponed = NULL;
187 if ((is_array($this->sequencedata["postponed"])) && (count($this->sequencedata["postponed"])))
188 {
189 $postponed = serialize($this->sequencedata["postponed"]);
190 }
191 $hidden = NULL;
192 if ((is_array($this->sequencedata["hidden"])) && (count($this->sequencedata["hidden"])))
193 {
194 $hidden = serialize($this->sequencedata["hidden"]);
195 }
196
197 $affectedRows = $ilDB->manipulateF("DELETE FROM tst_sequence WHERE active_fi = %s AND pass = %s",
198 array('integer','integer'),
199 array($this->active_id, $this->pass)
200 );
201
202 $affectedRows = $ilDB->insert("tst_sequence", array(
203 "active_fi" => array("integer", $this->active_id),
204 "pass" => array("integer", $this->pass),
205 "sequence" => array("clob", serialize($this->sequencedata["sequence"])),
206 "postponed" => array("text", $postponed),
207 "hidden" => array("text", $hidden),
208 "tstamp" => array("integer", time())
209 ));
210 }
211
215 private function saveNewlyCheckedQuestion()
216 {
217 if( (int)$this->newlyCheckedQuestion )
218 {
219 global $ilDB;
220
221 $ilDB->replace('tst_seq_qst_checked', array(
222 'active_fi' => array('integer', (int)$this->active_id),
223 'pass' => array('integer', (int)$this->pass),
224 'question_fi' => array('integer', (int)$this->newlyCheckedQuestion)
225 ), array());
226 }
227 }
228
229 function postponeQuestion($question_id)
230 {
231 if (!$this->isPostponedQuestion($question_id))
232 {
233 array_push($this->sequencedata["postponed"], intval($question_id));
234 }
235 }
236
237 function hideQuestion($question_id)
238 {
239 if (!$this->isHiddenQuestion($question_id))
240 {
241 array_push($this->sequencedata["hidden"], intval($question_id));
242 }
243 }
244
245 function isPostponedQuestion($question_id)
246 {
247 if (!is_array($this->sequencedata["postponed"])) return FALSE;
248 if (!in_array($question_id, $this->sequencedata["postponed"]))
249 {
250 return FALSE;
251 }
252 else
253 {
254 return TRUE;
255 }
256 }
257
258 function isHiddenQuestion($question_id)
259 {
260 if (!is_array($this->sequencedata["hidden"])) return FALSE;
261 if (!in_array($question_id, $this->sequencedata["hidden"]))
262 {
263 return FALSE;
264 }
265 else
266 {
267 return TRUE;
268 }
269 }
270
271 function isPostponedSequence($sequence)
272 {
273 if (!array_key_exists($sequence, $this->questions)) return FALSE;
274 if (!is_array($this->sequencedata["postponed"])) return FALSE;
275 if (!in_array($this->questions[$sequence], $this->sequencedata["postponed"]))
276 {
277 return FALSE;
278 }
279 else
280 {
281 return TRUE;
282 }
283 }
284
285 function isHiddenSequence($sequence)
286 {
287 if (!array_key_exists($sequence, $this->questions)) return FALSE;
288 if (!is_array($this->sequencedata["hidden"])) return FALSE;
289 if (!in_array($this->questions[$sequence], $this->sequencedata["hidden"]))
290 {
291 return FALSE;
292 }
293 else
294 {
295 return TRUE;
296 }
297 }
298
299 function postponeSequence($sequence)
300 {
301 if (!$this->isPostponedSequence($sequence))
302 {
303 if (array_key_exists($sequence, $this->questions))
304 {
305 if (!is_array($this->sequencedata["postponed"])) $this->sequencedata["postponed"] = array();
306 array_push($this->sequencedata["postponed"], intval($this->questions[$sequence]));
307 }
308 }
309 }
310
311 function hideSequence($sequence)
312 {
313 if (!$this->isHiddenSequence($sequence))
314 {
315 if (array_key_exists($sequence, $this->questions))
316 {
317 if (!is_array($this->sequencedata["hidden"])) $this->sequencedata["hidden"] = array();
318 array_push($this->sequencedata["hidden"], intval($this->questions[$sequence]));
319 }
320 }
321 }
322
323 public function setQuestionChecked($questionId)
324 {
325 $this->newlyCheckedQuestion = $questionId;
326 }
327
328 public function isQuestionChecked($questionId)
329 {
330 return isset($this->alreadyCheckedQuestions[$questionId]);
331 }
332
333 function getPositionOfSequence($sequence)
334 {
335 $correctedsequence = $this->getCorrectedSequence();
336 $sequencekey = array_search($sequence, $correctedsequence);
337 if ($sequencekey !== FALSE)
338 {
339 return $sequencekey + 1;
340 }
341 else
342 {
343 return "";
344 }
345 }
346
348 {
349 return count($this->getCorrectedSequence());
350 }
351
353 {
354 return array_keys($this->questions);
355 }
356
358 {
359 return $this->questions;
360 }
361
363 {
364 return $this->getCorrectedSequence(TRUE);
365 }
366
368 {
369 $seq = $this->getCorrectedSequence(TRUE);
370 $found = array();
371 foreach ($seq as $sequence)
372 {
373 array_push($found, $this->getQuestionForSequence($sequence));
374 }
375 return $found;
376 }
377
378 protected function getCorrectedSequence($with_hidden_questions = FALSE)
379 {
380 $correctedsequence = $this->sequencedata["sequence"];
381 if (!$with_hidden_questions)
382 {
383 if (is_array($this->sequencedata["hidden"]))
384 {
385 foreach ($this->sequencedata["hidden"] as $question_id)
386 {
387 $foundsequence = array_search($question_id, $this->questions);
388 if ($foundsequence !== FALSE)
389 {
390 $sequencekey = array_search($foundsequence, $correctedsequence);
391 if ($sequencekey !== FALSE)
392 {
393 unset($correctedsequence[$sequencekey]);
394 }
395 }
396 }
397 }
398 }
399 if (is_array($this->sequencedata["postponed"]))
400 {
401 foreach ($this->sequencedata["postponed"] as $question_id)
402 {
403 $foundsequence = array_search($question_id, $this->questions);
404 if ($foundsequence !== FALSE)
405 {
406 $sequencekey = array_search($foundsequence, $correctedsequence);
407 if ($sequencekey !== FALSE)
408 {
409 unset($correctedsequence[$sequencekey]);
410 array_push($correctedsequence, $foundsequence);
411 }
412 }
413 }
414 }
415 return array_values($correctedsequence);
416 }
417
418 function getSequenceForQuestion($question_id)
419 {
420 return array_search($question_id, $this->questions);
421 }
422
424 {
425 $correctedsequence = $this->getCorrectedSequence();
426 if (count($correctedsequence))
427 {
428 return reset($correctedsequence);
429 }
430 else
431 {
432 return FALSE;
433 }
434 }
435
437 {
438 $correctedsequence = $this->getCorrectedSequence();
439 if (count($correctedsequence))
440 {
441 return end($correctedsequence);
442 }
443 else
444 {
445 return FALSE;
446 }
447 }
448
449 function getNextSequence($sequence)
450 {
451 $correctedsequence = $this->getCorrectedSequence();
452 $sequencekey = array_search($sequence, $correctedsequence);
453 if ($sequencekey !== FALSE)
454 {
455 $nextsequencekey = $sequencekey + 1;
456 if (array_key_exists($nextsequencekey, $correctedsequence))
457 {
458 return $correctedsequence[$nextsequencekey];
459 }
460 }
461 return FALSE;
462 }
463
464 function getPreviousSequence($sequence)
465 {
466 $correctedsequence = $this->getCorrectedSequence();
467 $sequencekey = array_search($sequence, $correctedsequence);
468 if ($sequencekey !== FALSE)
469 {
470 $prevsequencekey = $sequencekey - 1;
471 if (($prevsequencekey >= 0) && (array_key_exists($prevsequencekey, $correctedsequence)))
472 {
473 return $correctedsequence[$prevsequencekey];
474 }
475 }
476 return FALSE;
477 }
478
487 function pcArrayShuffle($array)
488 {
489 $keys = array_keys($array);
490 shuffle($keys);
491 $result = array();
492 foreach ($keys as $key)
493 {
494 $result[$key] = $array[$key];
495 }
496 return $result;
497 }
498
499 function getQuestionForSequence($sequence)
500 {
501 if ($sequence < 1) return FALSE;
502 if (array_key_exists($sequence, $this->questions))
503 {
504 return $this->questions[$sequence];
505 }
506 else
507 {
508 return FALSE;
509 }
510 }
511
512 function &getSequenceSummary($obligationsFilter = false)
513 {
514 $correctedsequence = $this->getCorrectedSequence();
515 $result_array = array();
516 include_once "./Modules/Test/classes/class.ilObjTest.php";
517 $solved_questions = ilObjTest::_getSolvedQuestions($this->active_id);
518 $key = 1;
519 foreach ($correctedsequence as $sequence)
520 {
521 $question =& ilObjTest::_instanciateQuestion($this->getQuestionForSequence($sequence));
522 if (is_object($question))
523 {
524 $worked_through = $question->_isWorkedThrough($this->active_id, $question->getId(), $this->pass);
525 $solved = 0;
526 if (array_key_exists($question->getId(), $solved_questions))
527 {
528 $solved = $solved_questions[$question->getId()]["solved"];
529 }
530 $is_postponed = $this->isPostponedQuestion($question->getId());
531
532 $row = array(
533 "nr" => "$key",
534 "title" => $question->getTitle(),
535 "qid" => $question->getId(),
536 "visited" => $worked_through,
537 "solved" => (($solved)?"1":"0"),
538 "description" => $question->getComment(),
539 "points" => $question->getMaximumPoints(),
540 "worked_through" => $worked_through,
541 "postponed" => $is_postponed,
542 "sequence" => $sequence,
543 "obligatory" => ilObjTest::isQuestionObligatory($question->getId()),
544 'isAnswered' => $question->isAnswered($this->active_id, $this->pass)
545 );
546
547 if( !$obligationsFilter || $row['obligatory'] )
548 {
549 array_push($result_array, $row);
550 }
551
552 $key++;
553 }
554 }
555 return $result_array;
556 }
557
558 function getPass()
559 {
560 return $this->pass;
561 }
562
563 function setPass($pass)
564 {
565 $this->pass = $pass;
566 }
567
568 function hasSequence()
569 {
570 if ((is_array($this->sequencedata["sequence"])) && (count($this->sequencedata["sequence"]) > 0))
571 {
572 return TRUE;
573 }
574 else
575 {
576 return FALSE;
577 }
578 }
579
581 {
582 if ((is_array($this->sequencedata["hidden"])) && (count($this->sequencedata["hidden"]) > 0))
583 {
584 return TRUE;
585 }
586 else
587 {
588 return FALSE;
589 }
590 }
591
593 {
594 $this->sequencedata["hidden"] = array();
595 }
596
597 private function hideCorrectAnsweredQuestions(ilObjTest $testOBJ, $activeId, $pass)
598 {
599 if( $activeId > 0 )
600 {
601 $result = $testOBJ->getTestResult($activeId, $pass, TRUE);
602
603 foreach( $result as $sequence => $question )
604 {
605 if( is_numeric($sequence) )
606 {
607 if( $question['reached'] == $question['max'] )
608 {
609 $this->hideQuestion($question['qid']);
610 }
611 }
612 }
613
614 $this->saveToDb();
615 }
616 }
617
618 public function hasStarted(ilTestSession $testSession)
619 {
620 if( $testSession->getLastSequence() < 1 )
621 {
622 return false;
623 }
624
625 // WTF ?? heard about tests with only one question !?
626 if( $testSession->getLastSequence() == $this->getFirstSequence() )
627 {
628 return false;
629 }
630
631 return true;
632 }
633
634 public function openQuestionExists()
635 {
636 return $this->getFirstSequence() !== false;
637 }
638
639 public function getQuestionIds()
640 {
641 return array_values($this->questions);
642 }
643
644 public function questionExists($questionId)
645 {
646 return in_array($questionId, $this->questions);
647 }
648}
649
650?>
$result
& getTestResult($active_id, $pass=NULL, $ordered_sequence=FALSE)
Calculates the results of a test for a given user and returns an array with all test results.
_getSolvedQuestions($active_id, $question_fi=null)
get solved questions
& _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
Test sequence handler.
questionExists($questionId)
isHiddenQuestion($question_id)
getCorrectedSequence($with_hidden_questions=FALSE)
ilTestSequence($active_id, $pass, $randomtest)
ilTestSequence constructor
isPostponedSequence($sequence)
pcArrayShuffle($array)
Shuffles the values of a given array.
getQuestionForSequence($sequence)
hideQuestion($question_id)
setQuestionChecked($questionId)
isQuestionChecked($questionId)
& getSequenceSummary($obligationsFilter=false)
postponeQuestion($question_id)
loadQuestions(ilTestQuestionSetConfig $testQuestionSetConfig=null, $taxonomyFilterSelection=array())
Loads the question mapping.
saveToDb()
Saves the sequence data for a given pass to the database.
saveNewlyCheckedQuestion()
@global ilDB $ilDB
hasStarted(ilTestSession $testSession)
hideCorrectAnsweredQuestions(ilObjTest $testOBJ, $activeId, $pass)
getPositionOfSequence($sequence)
createNewSequence($max, $shuffle)
getPreviousSequence($sequence)
loadFromDb()
Loads the sequence data for a given active id.
getSequenceForQuestion($question_id)
isPostponedQuestion($question_id)
Test session handler.
global $ilDB