ILIAS  Release_5_0_x_branch Revision 61816
 All Data Structures Namespaces Files Functions Variables Groups Pages
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();
179  $this->saveNewlyCheckedQuestion();
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 
362  function getUserSequence()
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 
423  function getFirstSequence()
424  {
425  $correctedsequence = $this->getCorrectedSequence();
426  if (count($correctedsequence))
427  {
428  return reset($correctedsequence);
429  }
430  else
431  {
432  return FALSE;
433  }
434  }
435 
436  function getLastSequence()
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 ?>