ILIAS  release_5-0 Revision 5.0.0-1144-gc4397b1f870
All Data Structures Namespaces Files Functions Variables Modules Pages
class.assClozeTest.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
3 
4 require_once './Modules/TestQuestionPool/classes/class.assQuestion.php';
5 require_once './Modules/Test/classes/inc.AssessmentConstants.php';
6 require_once './Modules/TestQuestionPool/classes/class.assClozeGapCombination.php';
7 require_once './Modules/TestQuestionPool/interfaces/interface.ilObjQuestionScoringAdjustable.php';
8 require_once './Modules/TestQuestionPool/interfaces/interface.ilObjAnswerScoringAdjustable.php';
9 require_once './Modules/TestQuestionPool/interfaces/interface.iQuestionCondition.php';
10 require_once './Modules/TestQuestionPool/classes/class.ilUserQuestionResult.php';
11 
24 {
32  var $gaps;
33 
42 
43 
45 
54 
62  var $end_tag;
63 
75 
86 
93 
94  public $cloze_text;
95 
109  function __construct(
110  $title = "",
111  $comment = "",
112  $author = "",
113  $owner = -1,
114  $question = ""
115  )
116  {
117  parent::__construct($title, $comment, $author, $owner, $question);
118  $this->start_tag = "[gap]";
119  $this->end_tag = "[/gap]";
120  $this->gaps = array();
121  $this->setQuestion($question); // @TODO: Should this be $question?? See setter for why this is not trivial.
122  $this->fixedTextLength = "";
123  $this->identical_scoring = 1;
124  $this->gap_combinations_exists = false;
125  $this->gap_combinations = array();
126  }
127 
133  public function isComplete()
134  {
135  if (strlen($this->getTitle())
136  && $this->getAuthor()
137  && $this->getClozeText()
138  && count($this->getGaps())
139  && $this->getMaximumPoints() > 0)
140  {
141  return true;
142  }
143  return false;
144  }
145 
153  public function cleanQuestiontext($text)
154  {
155  $text = preg_replace("/\[gap[^\]]*?\]/", "[gap]", $text);
156  $text = preg_replace("/<gap([^>]*?)>/", "[gap]", $text);
157  $text = str_replace("</gap>", "[/gap]", $text);
158  return $text;
159  }
160 
167  public function loadFromDb($question_id)
168  {
169  global $ilDB;
170  $result = $ilDB->queryF("SELECT qpl_questions.*, " . $this->getAdditionalTableName() . ".* FROM qpl_questions LEFT JOIN " . $this->getAdditionalTableName() . " ON " . $this->getAdditionalTableName() . ".question_fi = qpl_questions.question_id WHERE qpl_questions.question_id = %s",
171  array("integer"),
172  array($question_id)
173  );
174  if ($result->numRows() == 1)
175  {
176  $data = $ilDB->fetchAssoc($result);
177  $this->setId($question_id);
178  $this->setNrOfTries($data['nr_of_tries']);
179  $this->setObjId($data["obj_fi"]);
180  $this->setTitle($data["title"]);
181  $this->setComment($data["description"]);
182  $this->setOriginalId($data["original_id"]);
183  $this->setAuthor($data["author"]);
184  $this->setPoints($data["points"]);
185  $this->setOwner($data["owner"]);
186  $this->setQuestion($this->cleanQuestiontext($data["question_text"]));
187  $this->setClozeText($data['cloze_text']);
188  $this->setFixedTextLength($data["fixed_textlen"]);
189  $this->setIdenticalScoring(($data['tstamp'] == 0) ? true : $data["identical_scoring"]);
190  // replacement of old syntax with new syntax
191  include_once("./Services/RTE/classes/class.ilRTE.php");
192  $this->question = ilRTE::_replaceMediaObjectImageSrc($this->question, 1);
193  $this->cloze_text = ilRTE::_replaceMediaObjectImageSrc($this->cloze_text, 1);
194  $this->setTextgapRating($data["textgap_rating"]);
195  $this->setEstimatedWorkingTime(substr($data["working_time"], 0, 2), substr($data["working_time"], 3, 2), substr($data["working_time"], 6, 2));
196 
197  try
198  {
199  $this->setAdditionalContentEditingMode($data['add_cont_edit_mode']);
200  }
202  {
203  }
204 
205  // open the cloze gaps with all answers
206  include_once "./Modules/TestQuestionPool/classes/class.assAnswerCloze.php";
207  include_once "./Modules/TestQuestionPool/classes/class.assClozeGap.php";
208  $result = $ilDB->queryF("SELECT * FROM qpl_a_cloze WHERE question_fi = %s ORDER BY gap_id, aorder ASC",
209  array("integer"),
210  array($question_id)
211  );
212  if ($result->numRows() > 0)
213  {
214  $this->gaps = array();
215  while ($data = $ilDB->fetchAssoc($result))
216  {
217  switch ($data["cloze_type"])
218  {
219  case CLOZE_TEXT:
220  if (!array_key_exists($data["gap_id"], $this->gaps))
221  {
222  $this->gaps[$data["gap_id"]] = new assClozeGap(CLOZE_TEXT);
223  }
224  $answer = new assAnswerCloze(
225  $data["answertext"],
226  $data["points"],
227  $data["aorder"]
228  );
229  $this->gaps[$data["gap_id"]]->setGapSize($data['gap_size']);
230 
231  $this->gaps[$data["gap_id"]]->addItem($answer);
232  break;
233  case CLOZE_SELECT:
234  if (!array_key_exists($data["gap_id"], $this->gaps))
235  {
236  $this->gaps[$data["gap_id"]] = new assClozeGap(CLOZE_SELECT);
237  $this->gaps[$data["gap_id"]]->setShuffle($data["shuffle"]);
238  }
239  $answer = new assAnswerCloze(
240  $data["answertext"],
241  $data["points"],
242  $data["aorder"]
243  );
244  $this->gaps[$data["gap_id"]]->addItem($answer);
245  break;
246  case CLOZE_NUMERIC:
247  if (!array_key_exists($data["gap_id"], $this->gaps))
248  {
249  $this->gaps[$data["gap_id"]] = new assClozeGap(CLOZE_NUMERIC);
250  }
251  $answer = new assAnswerCloze(
252  $data["answertext"],
253  $data["points"],
254  $data["aorder"]
255  );
256  $this->gaps[$data["gap_id"]]->setGapSize($data['gap_size']);
257  $answer->setLowerBound($data["lowerlimit"]);
258  $answer->setUpperBound($data["upperlimit"]);
259  $this->gaps[$data["gap_id"]]->addItem($answer);
260  break;
261  }
262  }
263  }
264  }
265  $assClozeGapCombinationObj = new assClozeGapCombination();
266  $check_for_gap_combinations = $assClozeGapCombinationObj->loadFromDb($question_id);
267  if(count($check_for_gap_combinations) != 0)
268  {
269  $this->setGapCombinationsExists(true);
270  $this->setGapCombinations($check_for_gap_combinations);
271  }
272  parent::loadFromDb($question_id);
273  }
274 
275  #region Save question to db
276 
286  public function saveToDb($original_id = "")
287  {
291 
292  parent::saveToDb($original_id);
293  }
294 
298  public function saveAnswerSpecificDataToDb()
299  {
300  global $ilDB;
301 
302  $ilDB->manipulateF( "DELETE FROM qpl_a_cloze WHERE question_fi = %s",
303  array( "integer" ),
304  array( $this->getId() )
305  );
306 
307  foreach ($this->gaps as $key => $gap)
308  {
309  $this->saveClozeGapItemsToDb( $gap, $key );
310  }
311  }
312 
319  {
320  global $ilDB;
321 
322  $ilDB->manipulateF( "DELETE FROM " . $this->getAdditionalTableName() . " WHERE question_fi = %s",
323  array( "integer" ),
324  array( $this->getId() )
325  );
326 
327  $ilDB->manipulateF( "INSERT INTO " . $this->getAdditionalTableName()
328  . " (question_fi, textgap_rating, identical_scoring, fixed_textlen, cloze_text) VALUES (%s, %s, %s, %s, %s)",
329  array(
330  "integer",
331  "text",
332  "text",
333  "integer",
334  "text"
335  ),
336  array(
337  $this->getId(),
338  $this->getTextgapRating(),
339  $this->getIdenticalScoring(),
340  $this->getFixedTextLength() ? $this->getFixedTextLength() : NULL,
342  )
343  );
344  }
345 
352  protected function saveClozeGapItemsToDb($gap, $key)
353  {
354  global $ilDB;
355  foreach ($gap->getItems() as $item)
356  {
357  $query = "";
358  $next_id = $ilDB->nextId( 'qpl_a_cloze' );
359  switch ($gap->getType())
360  {
361  case CLOZE_TEXT:
362  $this->saveClozeTextGapRecordToDb($next_id, $key, $item, $gap );
363  break;
364  case CLOZE_SELECT:
365  $this->saveClozeSelectGapRecordToDb($next_id, $key, $item, $gap );
366  break;
367  case CLOZE_NUMERIC:
368  $this->saveClozeNumericGapRecordToDb($next_id, $key, $item, $gap );
369  break;
370  }
371  }
372  }
373 
382  protected function saveClozeTextGapRecordToDb($next_id, $key, $item, $gap)
383  {
384  global $ilDB;
385  $ilDB->manipulateF( "INSERT INTO qpl_a_cloze (answer_id, question_fi, gap_id, answertext, points, aorder, cloze_type, gap_size) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)",
386  array(
387  "integer",
388  "integer",
389  "integer",
390  "text",
391  "float",
392  "integer",
393  "text",
394  "integer"
395  ),
396  array(
397  $next_id,
398  $this->getId(),
399  $key,
400  strlen( $item->getAnswertext() ) ? $item->getAnswertext() : "",
401  $item->getPoints(),
402  $item->getOrder(),
403  $gap->getType(),
404  (int)$gap->getGapSize()
405  )
406  );
407  }
408 
417  protected function saveClozeSelectGapRecordToDb($next_id, $key, $item, $gap)
418  {
419  global $ilDB;
420  $ilDB->manipulateF( "INSERT INTO qpl_a_cloze (answer_id, question_fi, gap_id, answertext, points, aorder, cloze_type, shuffle) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)",
421  array(
422  "integer",
423  "integer",
424  "integer",
425  "text",
426  "float",
427  "integer",
428  "text",
429  "text"
430  ),
431  array(
432  $next_id,
433  $this->getId(),
434  $key,
435  strlen( $item->getAnswertext() ) ? $item->getAnswertext() : "",
436  $item->getPoints(),
437  $item->getOrder(),
438  $gap->getType(),
439  ($gap->getShuffle()) ? "1" : "0"
440  )
441  );
442  }
443 
452  protected function saveClozeNumericGapRecordToDb($next_id, $key, $item, $gap)
453  {
454  global $ilDB;
455 
456  include_once "./Services/Math/classes/class.EvalMath.php";
457  $eval = new EvalMath();
458  $eval->suppress_errors = TRUE;
459  $ilDB->manipulateF( "INSERT INTO qpl_a_cloze (answer_id, question_fi, gap_id, answertext, points, aorder, cloze_type, lowerlimit, upperlimit, gap_size) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)",
460  array(
461  "integer",
462  "integer",
463  "integer",
464  "text",
465  "float",
466  "integer",
467  "text",
468  "text",
469  "text",
470  "integer"
471  ),
472  array(
473  $next_id,
474  $this->getId(),
475  $key,
476  strlen( $item->getAnswertext() ) ? $item->getAnswertext() : "",
477  $item->getPoints(),
478  $item->getOrder(),
479  $gap->getType(),
480  ($eval->e( $item->getLowerBound() !== FALSE ) && strlen( $item->getLowerBound()
481  ) > 0) ? $item->getLowerBound() : $item->getAnswertext(),
482  ($eval->e( $item->getUpperBound() !== FALSE ) && strlen( $item->getUpperBound()
483  ) > 0) ? $item->getUpperBound() : $item->getAnswertext(),
484  (int)$gap->getGapSize()
485  )
486  );
487  }
488 
489 
490 
491  #endregion Save question to db
492 
499  function getGaps()
500  {
501  return $this->gaps;
502  }
503 
504 
511  function flushGaps()
512  {
513  $this->gaps = array();
514  }
515 
525  function setClozeText($cloze_text = "")
526  {
527  $this->gaps = array();
529  $this->cloze_text = $cloze_text;
531  }
532 
534  {
535  $this->cloze_text = $cloze_text;
536  }
537 
545  function getClozeText()
546  {
547  return $this->cloze_text;
548  }
549 
557  function getStartTag()
558  {
559  return $this->start_tag;
560  }
561 
569  function setStartTag($start_tag = "[gap]")
570  {
571  $this->start_tag = $start_tag;
572  }
573 
581  function getEndTag()
582  {
583  return $this->end_tag;
584  }
585 
593  function setEndTag($end_tag = "[/gap]")
594  {
595  $this->end_tag = $end_tag;
596  }
597 
605  {
606  include_once "./Modules/TestQuestionPool/classes/class.assClozeGap.php";
607  include_once "./Modules/TestQuestionPool/classes/class.assAnswerCloze.php";
608  $search_pattern = "|\[gap\](.*?)\[/gap\]|i";
609  preg_match_all($search_pattern, $this->getClozeText(), $found);
610  $this->gaps = array();
611  if (count($found[0]))
612  {
613  foreach ($found[1] as $gap_index => $answers)
614  {
615  // create text gaps by default
616  $gap = new assClozeGap(CLOZE_TEXT);
617  $textparams = preg_split("/(?<!\\\\),/", $answers);
618  foreach ($textparams as $key => $value)
619  {
620  $answer = new assAnswerCloze($value, 0, $key);
621  $gap->addItem($answer);
622  }
623  $this->gaps[$gap_index] = $gap;
624  }
625  }
626  }
627 
633  function setGapType($gap_index, $gap_type)
634  {
635  if (array_key_exists($gap_index, $this->gaps))
636  {
637  $this->gaps[$gap_index]->setType($gap_type);
638  }
639  }
640 
650  function setGapShuffle($gap_index = 0, $shuffle = 1)
651  {
652  if (array_key_exists($gap_index, $this->gaps))
653  {
654  $this->gaps[$gap_index]->setShuffle($shuffle);
655  }
656  }
657 
664  function clearGapAnswers()
665  {
666  foreach ($this->gaps as $gap_index => $gap)
667  {
668  $this->gaps[$gap_index]->clearItems();
669  }
670  }
671 
679  function getGapCount()
680  {
681  if (is_array($this->gaps))
682  {
683  return count($this->gaps);
684  }
685  else
686  {
687  return 0;
688  }
689  }
690 
701  function addGapAnswer($gap_index, $order, $answer)
702  {
703  if (array_key_exists($gap_index, $this->gaps))
704  {
705  if ($this->gaps[$gap_index]->getType() == CLOZE_NUMERIC)
706  {
707  // only allow notation with "." for real numbers
708  $answer = str_replace(",", ".", $answer);
709  }
710  $this->gaps[$gap_index]->addItem(new assAnswerCloze($answer, 0, $order));
711  }
712  }
713 
722  function getGap($gap_index = 0)
723  {
724  if (array_key_exists($gap_index, $this->gaps))
725  {
726  return $this->gaps[$gap_index];
727  }
728  else
729  {
730  return NULL;
731  }
732  }
733 
734  public function setGapSize($gap_index, $order, $size)
735  {
736  if (array_key_exists($gap_index, $this->gaps))
737  {
738  $this->gaps[$gap_index]->setGapSize( $size);
739  }
740  }
741 
752  function setGapAnswerPoints($gap_index, $order, $points)
753  {
754  if (array_key_exists($gap_index, $this->gaps))
755  {
756  $this->gaps[$gap_index]->setItemPoints($order, $points);
757  }
758  }
759 
768  function addGapText($gap_index)
769  {
770  if (array_key_exists($gap_index, $this->gaps))
771  {
772  include_once "./Modules/TestQuestionPool/classes/class.assAnswerCloze.php";
773  $answer = new assAnswerCloze(
774  "",
775  0,
776  $this->gaps[$gap_index]->getItemCount()
777  );
778  $this->gaps[$gap_index]->addItem($answer);
779  }
780  }
781 
790  function addGapAtIndex($gap, $index)
791  {
792  $this->gaps[$index] = $gap;
793  }
794 
805  function setGapAnswerLowerBound($gap_index, $order, $bound)
806  {
807  if (array_key_exists($gap_index, $this->gaps))
808  {
809  $this->gaps[$gap_index]->setItemLowerBound($order, $bound);
810  }
811  }
812 
823  function setGapAnswerUpperBound($gap_index, $order, $bound)
824  {
825  if (array_key_exists($gap_index, $this->gaps))
826  {
827  $this->gaps[$gap_index]->setItemUpperBound($order, $bound);
828  }
829  }
830 
837  function getMaximumPoints()
838  {
839  $assClozeGapCombinationObj = new assClozeGapCombination();
840  $points = 0;
841  $gaps_used_in_combination = array();
842  if($assClozeGapCombinationObj->combinationExistsForQid($this->getId()))
843  {
844  $points = $assClozeGapCombinationObj->getMaxPointsForCombination($this->getId());
845  $gaps_used_in_combination = $assClozeGapCombinationObj->getGapsWhichAreUsedInCombination($this->getId());
846  }
847  foreach ($this->gaps as $gap_index => $gap)
848  {
849  if(! array_key_exists($gap_index, $gaps_used_in_combination))
850  {
851  if ($gap->getType() == CLOZE_TEXT)
852  {
853  $gap_max_points = 0;
854  foreach ($gap->getItems() as $item)
855  {
856  if ($item->getPoints() > $gap_max_points)
857  {
858  $gap_max_points = $item->getPoints();
859  }
860  }
861  $points += $gap_max_points;
862  }
863  else if ($gap->getType() == CLOZE_SELECT)
864  {
865  $srpoints = 0;
866  foreach ($gap->getItems() as $item)
867  {
868  if ($item->getPoints() > $srpoints)
869  {
870  $srpoints = $item->getPoints();
871  }
872  }
873  $points += $srpoints;
874  }
875  else if ($gap->getType() == CLOZE_NUMERIC)
876  {
877  $numpoints = 0;
878  foreach ($gap->getItems() as $item)
879  {
880  if ($item->getPoints() > $numpoints)
881  {
882  $numpoints = $item->getPoints();
883  }
884  }
885  $points += $numpoints;
886  }
887  }
888  }
889 
890  return $points;
891  }
892 
898  function duplicate($for_test = true, $title = "", $author = "", $owner = "", $testObjId = null)
899  {
900  if ($this->id <= 0)
901  {
902  // The question has not been saved. It cannot be duplicated
903  return;
904  }
905  // duplicate the question in database
906  $this_id = $this->getId();
907  $thisObjId = $this->getObjId();
908 
909  $clone = $this;
910  include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
912  $clone->id = -1;
913 
914  if( (int)$testObjId > 0 )
915  {
916  $clone->setObjId($testObjId);
917  }
918 
919  if ($title)
920  {
921  $clone->setTitle($title);
922  }
923  if ($author)
924  {
925  $clone->setAuthor($author);
926  }
927  if ($owner)
928  {
929  $clone->setOwner($owner);
930  }
931  if ($for_test)
932  {
933  $clone->saveToDb($original_id);
934  }
935  else
936  {
937  $clone->saveToDb();
938  }
939  if($this->gap_combinations_exists)
940  {
941  $this->copyGapCombination($this_id, $clone->getId());
942  }
943  if ($for_test)
944  {
945  $clone->saveToDb($original_id);
946  }
947  else
948  {
949  $clone->saveToDb();
950  }
951  // copy question page content
952  $clone->copyPageOfQuestion($this_id);
953  // copy XHTML media objects
954  $clone->copyXHTMLMediaObjectsOfQuestion($this_id);
955 
956  $clone->onDuplicate($thisObjId, $this_id, $clone->getObjId(), $clone->getId());
957 
958  return $clone->getId();
959  }
960 
966  function copyObject($target_questionpool_id, $title = "")
967  {
968  if ($this->getId() <= 0)
969  {
970  // The question has not been saved. It cannot be duplicated
971  return;
972  }
973 
974  $thisId = $this->getId();
975  $thisObjId = $this->getObjId();
976 
977  $clone = $this;
978  include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
980  $clone->id = -1;
981  $clone->setObjId($target_questionpool_id);
982  if ($title)
983  {
984  $clone->setTitle($title);
985  }
986 
987  $clone->saveToDb();
988 
989  if($this->gap_combinations_exists)
990  {
991  $this->copyGapCombination($original_id, $clone->getId());
992  $clone->saveToDb();
993  }
994 
995  // copy question page content
996  $clone->copyPageOfQuestion($original_id);
997  // copy XHTML media objects
998  $clone->copyXHTMLMediaObjectsOfQuestion($original_id);
999 
1000  $clone->onCopy($thisObjId, $thisId, $clone->getObjId(), $clone->getId());
1001 
1002  return $clone->getId();
1003  }
1004 
1005  public function createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle = "")
1006  {
1007  if ($this->id <= 0)
1008  {
1009  // The question has not been saved. It cannot be duplicated
1010  return;
1011  }
1012 
1013  include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
1014 
1015  $sourceQuestionId = $this->id;
1016  $sourceParentId = $this->getObjId();
1017 
1018  // duplicate the question in database
1019  $clone = $this;
1020  $clone->id = -1;
1021 
1022  $clone->setObjId($targetParentId);
1023 
1024  if ($targetQuestionTitle)
1025  {
1026  $clone->setTitle($targetQuestionTitle);
1027  }
1028 
1029  $clone->saveToDb();
1030 
1031  if($this->gap_combinations_exists)
1032  {
1033  $this->copyGapCombination($sourceQuestionId, $clone->getId());
1034  }
1035  // copy question page content
1036  $clone->copyPageOfQuestion($sourceQuestionId);
1037  // copy XHTML media objects
1038  $clone->copyXHTMLMediaObjectsOfQuestion($sourceQuestionId);
1039 
1040  $clone->onCopy($sourceParentId, $sourceQuestionId, $clone->getObjId(), $clone->getId());
1041 
1042  return $clone->id;
1043  }
1044 
1045  function copyGapCombination($orgID, $newID)
1046  {
1047  $assClozeGapCombinationObj = new assClozeGapCombination();
1048  $array = $assClozeGapCombinationObj->loadFromDb($orgID);
1049  $assClozeGapCombinationObj->importGapCombinationToDb($newID , $array);
1050  }
1051 
1058  {
1059  $output = $this->getClozeText();
1060  foreach ($this->getGaps() as $gap_index => $gap)
1061  {
1062  $answers = array();
1063  foreach ($gap->getItemsRaw() as $item)
1064  {
1065  array_push($answers, str_replace(",", "\\,", $item->getAnswerText()));
1066  }
1067  $output = preg_replace("/\[gap\].*?\[\/gap\]/", "[_gap]" . $this->prepareTextareaOutput(join(",", $answers), true) . "[/_gap]", $output, 1);
1068  }
1069  $output = str_replace("_gap]", "gap]", $output);
1070  $this->cloze_text = $output;
1071  }
1072 
1082  function deleteAnswerText($gap_index, $answer_index)
1083  {
1084  if (array_key_exists($gap_index, $this->gaps))
1085  {
1086  if ($this->gaps[$gap_index]->getItemCount() == 1)
1087  {
1088  // this is the last answer text => remove the gap
1089  $this->deleteGap($gap_index);
1090  }
1091  else
1092  {
1093  // remove the answer text
1094  $this->gaps[$gap_index]->deleteItem($answer_index);
1095  $this->updateClozeTextFromGaps();
1096  }
1097  }
1098  }
1099 
1108  function deleteGap($gap_index)
1109  {
1110  if (array_key_exists($gap_index, $this->gaps))
1111  {
1112  $output = $this->getClozeText();
1113  foreach ($this->getGaps() as $replace_gap_index => $gap)
1114  {
1115  $answers = array();
1116  foreach ($gap->getItemsRaw() as $item)
1117  {
1118  array_push($answers, str_replace(",", "\\,", $item->getAnswerText()));
1119  }
1120  if ($replace_gap_index == $gap_index)
1121  {
1122  $output = preg_replace("/\[gap\].*?\[\/gap\]/", "", $output, 1);
1123  }
1124  else
1125  {
1126  $output = preg_replace("/\[gap\].*?\[\/gap\]/", "[_gap]" . join(",", $answers) . "[/_gap]", $output, 1);
1127  }
1128  }
1129  $output = str_replace("_gap]", "gap]", $output);
1130  $this->cloze_text = $output;
1131  unset($this->gaps[$gap_index]);
1132  $this->gaps = array_values($this->gaps);
1133  }
1134  }
1135 
1145  function getTextgapPoints($a_original, $a_entered, $max_points)
1146  {
1147  include_once "./Services/Utilities/classes/class.ilStr.php";
1148  $result = 0;
1149  $gaprating = $this->getTextgapRating();
1150  switch ($gaprating)
1151  {
1153  if (strcmp(ilStr::strToLower($a_original), ilStr::strToLower($a_entered)) == 0) $result = $max_points;
1154  break;
1156  if (strcmp($a_original, $a_entered) == 0) $result = $max_points;
1157  break;
1159  if (levenshtein($a_original, $a_entered) <= 1) $result = $max_points;
1160  break;
1162  if (levenshtein($a_original, $a_entered) <= 2) $result = $max_points;
1163  break;
1165  if (levenshtein($a_original, $a_entered) <= 3) $result = $max_points;
1166  break;
1168  if (levenshtein($a_original, $a_entered) <= 4) $result = $max_points;
1169  break;
1171  if (levenshtein($a_original, $a_entered) <= 5) $result = $max_points;
1172  break;
1173  }
1174  return $result;
1175  }
1176 
1186  function getNumericgapPoints($a_original, $a_entered, $max_points, $lowerBound, $upperBound)
1187  {
1188 // fau: fixGapFormula - check entered value by evalMath
1189 // if( ! $this->checkForValidFormula($a_entered) )
1190 // {
1191 // return 0;
1192 // }
1193 
1194  include_once "./Services/Math/classes/class.EvalMath.php";
1195  $eval = new EvalMath();
1196  $eval->suppress_errors = TRUE;
1197  $result = 0;
1198 
1199  if ($eval->e($a_entered) === FALSE)
1200  {
1201  return 0;
1202  }
1203  elseif (($eval->e($lowerBound) !== FALSE) && ($eval->e($upperBound) !== FALSE))
1204 // fau.
1205  {
1206  if (($eval->e($a_entered) >= $eval->e($lowerBound)) && ($eval->e($a_entered) <= $eval->e($upperBound))) $result = $max_points;
1207  }
1208  else if ($eval->e($lowerBound) !== FALSE)
1209  {
1210  if (($eval->e($a_entered) >= $eval->e($lowerBound)) && ($eval->e($a_entered) <= $eval->e($a_original))) $result = $max_points;
1211  }
1212  else if ($eval->e($upperBound) !== FALSE)
1213  {
1214  if (($eval->e($a_entered) >= $eval->e($a_original)) && ($eval->e($a_entered) <= $eval->e($upperBound))) $result = $max_points;
1215  }
1216  else
1217  {
1218  if ($eval->e($a_entered) == $eval->e($a_original)) $result = $max_points;
1219  }
1220  return $result;
1221  }
1222 
1227  public function checkForValidFormula($value)
1228  {
1229  return preg_match("/^-?(\\d*)(,|\\.|\\/){0,1}(\\d*)$/", $value, $matches);
1230  }
1241  public function calculateReachedPoints($active_id, $pass = NULL, $returndetails = FALSE)
1242  {
1243  global $ilDB;
1244 
1245  if (is_null($pass))
1246  {
1247  $pass = $this->getSolutionMaxPass($active_id);
1248  }
1249 
1250  $result = $this->getCurrentSolutionResultSet($active_id, $pass);
1251  $user_result = array();
1252  while ($data = $ilDB->fetchAssoc($result))
1253  {
1254  if (strcmp($data["value2"], "") != 0)
1255  {
1256  $user_result[$data["value1"]] = array(
1257  "gap_id" => $data["value1"],
1258  "value" => $data["value2"]
1259  );
1260  }
1261  }
1262 
1263  ksort($user_result); // this is required when identical scoring for same solutions is disabled
1264 
1265  if ($returndetails)
1266  {
1267  $detailed = array();
1268  $this->calculateReachedPointsForSolution($user_result, $detailed);
1269  return $detailed;
1270  }
1271 
1272  return $this->calculateReachedPointsForSolution($user_result);
1273  }
1274 
1275  public function getSolutionSubmit()
1276  {
1277  $solutionSubmit = array();
1278 
1279  foreach ($_POST as $key => $value)
1280  {
1281  if (preg_match("/^gap_(\d+)/", $key, $matches))
1282  {
1283  $value = ilUtil::stripSlashes($value, FALSE);
1284  if (strlen($value))
1285  {
1286  $gap = $this->getGap($matches[1]);
1287  if (is_object($gap))
1288  {
1289  if (!(($gap->getType() == CLOZE_SELECT) && ($value == -1)))
1290  {
1291  if ($gap->getType() == CLOZE_NUMERIC)
1292  {
1293  $value = str_replace(",", ".", $value);
1294  }
1295  $solutionSubmit[trim($matches[1])] = $value;
1296  }
1297  }
1298  }
1299  }
1300  }
1301 
1302  return $solutionSubmit;
1303  }
1304 
1313  public function saveWorkingData($active_id, $pass = NULL)
1314  {
1315  global $ilDB;
1316  global $ilUser;
1317  if (is_null($pass))
1318  {
1319  include_once "./Modules/Test/classes/class.ilObjTest.php";
1320  $pass = ilObjTest::_getPass($active_id);
1321  }
1322 
1323  $this->getProcessLocker()->requestUserSolutionUpdateLock();
1324 
1325  $affectedRows = $this->removeCurrentSolution($active_id, $pass);
1326 
1327  $entered_values = 0;
1328 
1329  foreach($this->getSolutionSubmit() as $val1 => $val2)
1330  {
1331  $value = trim(ilUtil::stripSlashes($val2, FALSE));
1332  if (strlen($value))
1333  {
1334  $gap = $this->getGap(trim(ilUtil::stripSlashes($val1)));
1335  if (is_object($gap))
1336  {
1337  if (!(($gap->getType() == CLOZE_SELECT) && ($value == -1)))
1338  {
1339  $affectedRows = $this->saveCurrentSolution($active_id,$pass, $val1, $value);
1340  $entered_values++;
1341  }
1342  }
1343  }
1344  }
1345 
1346  $this->getProcessLocker()->releaseUserSolutionUpdateLock();
1347 
1348  if ($entered_values)
1349  {
1350  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
1352  {
1353  $this->logAction($this->lng->txtlng("assessment", "log_user_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
1354  }
1355  }
1356  else
1357  {
1358  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
1360  {
1361  $this->logAction($this->lng->txtlng("assessment", "log_user_not_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
1362  }
1363  }
1364 
1365  return TRUE;
1366  }
1367 
1376  protected function reworkWorkingData($active_id, $pass, $obligationsAnswered)
1377  {
1378  // nothing to rework!
1379  }
1380 
1387  function getQuestionType()
1388  {
1389  return "assClozeTest";
1390  }
1391 
1399  function getTextgapRating()
1400  {
1401  return $this->textgap_rating;
1402  }
1403 
1411  function setTextgapRating($a_textgap_rating)
1412  {
1413  switch ($a_textgap_rating)
1414  {
1422  $this->textgap_rating = $a_textgap_rating;
1423  break;
1424  default:
1425  $this->textgap_rating = TEXTGAP_RATING_CASEINSENSITIVE;
1426  break;
1427  }
1428  }
1429 
1438  {
1439  return ($this->identical_scoring) ? 1 : 0;
1440  }
1441 
1449  function setIdenticalScoring($a_identical_scoring)
1450  {
1451  $this->identical_scoring = ($a_identical_scoring) ? 1 : 0;
1452  }
1453 
1461  {
1462  return "qpl_qst_cloze";
1463  }
1464 
1472  {
1473  return array("qpl_a_cloze",'qpl_a_cloze_combi_res');
1474  }
1475 
1482  function setFixedTextLength($a_text_len)
1483  {
1484  $this->fixedTextLength = $a_text_len;
1485  }
1486 
1494  {
1495  return $this->fixedTextLength;
1496  }
1497 
1506  function getMaximumGapPoints($gap_index)
1507  {
1508  $points = 0;
1509  $gap_max_points = 0;
1510  if (array_key_exists($gap_index, $this->gaps))
1511  {
1512  $gap =& $this->gaps[$gap_index];
1513  foreach ($gap->getItems() as $answer)
1514  {
1515  if ($answer->getPoints() > $gap_max_points)
1516  {
1517  $gap_max_points = $answer->getPoints();
1518  }
1519  }
1520  $points += $gap_max_points;
1521  }
1522  return $points;
1523  }
1524 
1530  {
1531  return parent::getRTETextWithMediaObjects() . $this->getClozeText();
1532  }
1534  {
1536  }
1537 
1539  {
1540  return $this->gap_combinations;
1541  }
1542 
1543  function setGapCombinationsExists($value)
1544  {
1545  $this->gap_combinations_exists = $value;
1546  }
1547 
1548  function setGapCombinations($value)
1549  {
1550  $this->gap_combinations = $value;
1551  }
1564  public function setExportDetailsXLS(&$worksheet, $startrow, $active_id, $pass, &$format_title, &$format_bold)
1565  {
1566  include_once ("./Services/Excel/classes/class.ilExcelUtils.php");
1567  $solution = $this->getSolutionValues($active_id, $pass);
1568  $worksheet->writeString($startrow, 0, ilExcelUtils::_convert_text($this->lng->txt($this->getQuestionType())), $format_title);
1569  $worksheet->writeString($startrow, 1, ilExcelUtils::_convert_text($this->getTitle()), $format_title);
1570  $i = 1;
1571  foreach ($this->getGaps() as $gap_index => $gap)
1572  {
1573  $worksheet->writeString($startrow + $i, 0, ilExcelUtils::_convert_text($this->lng->txt("gap") . " $i"), $format_bold);
1574  $checked = FALSE;
1575  foreach ($solution as $solutionvalue)
1576  {
1577  if ($gap_index == $solutionvalue["value1"])
1578  {
1579  switch ($gap->getType())
1580  {
1581  case CLOZE_SELECT:
1582  $worksheet->writeString($startrow + $i, 1, $gap->getItem($solutionvalue["value2"])->getAnswertext());
1583  break;
1584  case CLOZE_NUMERIC:
1585  case CLOZE_TEXT:
1586  $worksheet->writeString($startrow + $i, 1, $solutionvalue["value2"]);
1587  break;
1588  }
1589  }
1590  }
1591  $i++;
1592  }
1593  return $startrow + $i + 1;
1594  }
1595 
1599  public function toJSON()
1600  {
1601  include_once("./Services/RTE/classes/class.ilRTE.php");
1602  $result = array();
1603  $result['id'] = (int) $this->getId();
1604  $result['type'] = (string) $this->getQuestionType();
1605  $result['title'] = (string) $this->getTitle();
1606  $result['question'] = $this->formatSAQuestion(
1607  $this->getQuestion() . '<br/>' . $this->getClozeText()
1608  );
1609  $result['nr_of_tries'] = (int) $this->getNrOfTries();
1610  $result['shuffle'] = (bool) $this->getShuffle();
1611  $result['feedback'] = array(
1612  'onenotcorrect' => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), false)),
1613  'allcorrect' => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), true))
1614  );
1615 
1616  $gaps = array();
1617  foreach ($this->getGaps() as $key => $gap)
1618  {
1619  $items = array();
1620  foreach ($gap->getItems() as $item)
1621  {
1622  $jitem = array();
1623  $jitem['points'] = $item->getPoints();
1624  $jitem['value'] = $this->formatSAQuestion($item->getAnswertext());
1625  $jitem['order'] = $item->getOrder();
1626  if ($gap->getType() == CLOZE_NUMERIC)
1627  {
1628  $jitem['lowerbound'] = $item->getLowerBound();
1629  $jitem['upperbound'] = $item->getUpperBound();
1630  }
1631  else
1632  {
1633  $jitem['value'] = trim($jitem['value']);
1634  }
1635  array_push($items, $jitem);
1636  }
1637 
1638  if( $gap->getGapSize() && ($gap->getType() == CLOZE_TEXT || $gap->getType() == CLOZE_NUMERIC) )
1639  {
1640  $jgap['size'] = $gap->getGapSize();
1641  }
1642 
1643  $jgap['shuffle'] = $gap->getShuffle();
1644  $jgap['type'] = $gap->getType();
1645  $jgap['item'] = $items;
1646 
1647  array_push($gaps, $jgap);
1648  }
1649  $result['gaps'] = $gaps;
1650  $mobs = ilObjMediaObject::_getMobsOfObject("qpl:html", $this->getId());
1651  $result['mobs'] = $mobs;
1652  return json_encode($result);
1653  }
1654 
1663  public function getOperators($expression)
1664  {
1665  require_once "./Modules/TestQuestionPool/classes/class.ilOperatorsExpressionMapping.php";
1667  }
1668 
1673  public function getExpressionTypes()
1674  {
1675  return array(
1681  );
1682  }
1683 
1692  public function getUserQuestionResult($active_id, $pass)
1693  {
1695  global $ilDB;
1696  $result = new ilUserQuestionResult($this, $active_id, $pass);
1697 
1698  $data = $ilDB->queryF(
1699  "SELECT sol.value1+1 as val, sol.value2, cloze.cloze_type FROM tst_solutions sol INNER JOIN qpl_a_cloze cloze ON cloze.gap_id = value1 AND cloze.question_fi = sol.question_fi WHERE sol.active_fi = %s AND sol.pass = %s AND sol.question_fi = %s AND sol.step = (
1700  SELECT MAX(step) FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s
1701  ) GROUP BY sol.solution_id",
1702  array("integer", "integer", "integer","integer", "integer", "integer"),
1703  array($active_id, $pass, $this->getId(), $active_id, $pass, $this->getId())
1704  );
1705 
1706  while($row = $ilDB->fetchAssoc($data))
1707  {
1708  if($row["cloze_type"] == 1)
1709  {
1710  $row["value2"]++;
1711  }
1712  $result->addKeyValue($row["val"], $row["value2"]);
1713  }
1714 
1715  $points = $this->calculateReachedPoints($active_id, $pass);
1716  $max_points = $this->getMaximumPoints();
1717 
1718  $result->setReachedPercentage(($points/$max_points) * 100);
1719 
1720  return $result;
1721  }
1722 
1731  public function getAvailableAnswerOptions($index = null)
1732  {
1733  if($index !== null)
1734  {
1735  return $this->getGap($index);
1736  }
1737  else
1738  {
1739  return $this->getGaps();
1740  }
1741  }
1742 
1743  public function calculateCombinationResult($user_result)
1744  {
1745  $points = 0;
1746 
1747  $assClozeGapCombinationObj = new assClozeGapCombination();
1748 
1749  if($assClozeGapCombinationObj->combinationExistsForQid($this->getId()))
1750  {
1751  $combinations_for_question = $assClozeGapCombinationObj->getCleanCombinationArray($this->getId());
1752  $gap_answers = array();
1753  $gap_used_in_combination = array();
1754  foreach($user_result as $user_result_build_list)
1755  {
1756  if(is_array($user_result_build_list))
1757  {
1758  $gap_answers[$user_result_build_list['gap_id']] = $user_result_build_list['value'];
1759  }
1760  }
1761 
1762  foreach($combinations_for_question as $combination)
1763  {
1764 
1765  foreach($combination as $row_key => $row_answers)
1766  {
1767  $combination_fulfilled = true;
1768  $points_for_combination = $row_answers['points'];
1769  foreach($row_answers as $gap_key => $combination_gap_answer)
1770  {
1771  if($gap_key !== 'points')
1772  {
1773  $gap_used_in_combination[$gap_key]= $gap_key;
1774  }
1775  if($combination_fulfilled && array_key_exists($gap_key, $gap_answers))
1776  {
1777  switch($combination_gap_answer['type'])
1778  {
1779  case CLOZE_TEXT:
1780  $is_text_gap_correct = $this->getTextgapPoints($gap_answers[$gap_key], $combination_gap_answer['answer'], 1);
1781  if($is_text_gap_correct != 1)
1782  {
1783  $combination_fulfilled = false;
1784  }
1785  break;
1786  case CLOZE_SELECT:
1787  $answer = $this->gaps[$gap_key]->getItem($gap_answers[$gap_key]);
1788  $answertext = $answer->getAnswertext();
1789  if($answertext != $combination_gap_answer['answer'])
1790  {
1791  $combination_fulfilled = false;
1792  }
1793  break;
1794  case CLOZE_NUMERIC:
1795  $answer = $this->gaps[$gap_key]->getItem(0);
1796  if($combination_gap_answer['answer'] != 'out_of_bound')
1797  {
1798  $is_numeric_gap_correct = $this->getNumericgapPoints($answer->getAnswertext(), $gap_answers[$gap_key], 1, $answer->getLowerBound(), $answer->getUpperBound());
1799  if($is_numeric_gap_correct != 1)
1800  {
1801  $combination_fulfilled = false;
1802  }
1803  }
1804  else
1805  {
1806  $wrong_is_the_new_right = $this->getNumericgapPoints($answer->getAnswertext(), $gap_answers[$gap_key], 1, $answer->getLowerBound(), $answer->getUpperBound());
1807  if($wrong_is_the_new_right == 1)
1808  {
1809  $combination_fulfilled = false;
1810  }
1811  }
1812  break;
1813  }
1814  }
1815  else
1816  {
1817  if($gap_key !== 'points')
1818  {
1819  $combination_fulfilled = false;
1820  }
1821  }
1822  }
1823  if($combination_fulfilled)
1824  {
1825  $points += $points_for_combination;
1826  }
1827  }
1828  }
1829  }
1830  return array($points, $gap_used_in_combination);
1831  }
1837  protected function calculateReachedPointsForSolution($user_result, &$detailed = null)
1838  {
1839  if($detailed === null)
1840  {
1841  $detailed = array();
1842  }
1843 
1844  $assClozeGapCombinationObj = new assClozeGapCombination();
1845  $combinations[1] = array();
1846  if($assClozeGapCombinationObj->combinationExistsForQid($this->getId()))
1847  {
1848  $combinations = $this->calculateCombinationResult($user_result);
1849  $points = $combinations[0];
1850  }
1851  $counter = 0;
1852  $solution_values_text = array(); // for identical scoring checks
1853  $solution_values_select = array(); // for identical scoring checks
1854  $solution_values_numeric = array(); // for identical scoring checks
1855  foreach($user_result as $gap_id => $value)
1856  {
1857  if(is_string($value))
1858  {
1859  $value = array("value" => $value);
1860  }
1861 
1862  if(array_key_exists($gap_id, $this->gaps) && !array_key_exists ($gap_id, $combinations[1]))
1863  {
1864  switch($this->gaps[$gap_id]->getType())
1865  {
1866  case CLOZE_TEXT:
1867  $gappoints = 0;
1868  for($order = 0; $order < $this->gaps[$gap_id]->getItemCount(); $order++)
1869  {
1870  $answer = $this->gaps[$gap_id]->getItem($order);
1871  $gotpoints = $this->getTextgapPoints($answer->getAnswertext(), $value["value"], $answer->getPoints());
1872  if($gotpoints > $gappoints) $gappoints = $gotpoints;
1873  }
1874  if(!$this->getIdenticalScoring())
1875  {
1876  // check if the same solution text was already entered
1877  if((in_array($value["value"], $solution_values_text)) && ($gappoints > 0))
1878  {
1879  $gappoints = 0;
1880  }
1881  }
1882  $points += $gappoints;
1883  $detailed[$gap_id] = array("points" => $gappoints, "best" => ($this->getMaximumGapPoints($gap_id) == $gappoints) ? TRUE : FALSE, "positive" => ($gappoints > 0) ? TRUE : FALSE);
1884  array_push($solution_values_text, $value["value"]);
1885  break;
1886  case CLOZE_NUMERIC:
1887  $gappoints = 0;
1888  for($order = 0; $order < $this->gaps[$gap_id]->getItemCount(); $order++)
1889  {
1890  $answer = $this->gaps[$gap_id]->getItem($order);
1891  $gotpoints = $this->getNumericgapPoints($answer->getAnswertext(), $value["value"], $answer->getPoints(), $answer->getLowerBound(), $answer->getUpperBound());
1892  if($gotpoints > $gappoints) $gappoints = $gotpoints;
1893  }
1894  if(!$this->getIdenticalScoring())
1895  {
1896  // check if the same solution value was already entered
1897  include_once "./Services/Math/classes/class.EvalMath.php";
1898  $eval = new EvalMath();
1899  $eval->suppress_errors = TRUE;
1900  $found_value = FALSE;
1901  foreach($solution_values_numeric as $solval)
1902  {
1903  if($eval->e($solval) == $eval->e($value["value"]))
1904  {
1905  $found_value = TRUE;
1906  }
1907  }
1908  if($found_value && ($gappoints > 0))
1909  {
1910  $gappoints = 0;
1911  }
1912  }
1913  $points += $gappoints;
1914  $detailed[$gap_id] = array("points" => $gappoints, "best" => ($this->getMaximumGapPoints($gap_id) == $gappoints) ? TRUE : FALSE, "positive" => ($gappoints > 0) ? TRUE : FALSE);
1915  array_push($solution_values_numeric, $value["value"]);
1916  break;
1917  case CLOZE_SELECT:
1918  if($value["value"] >= 0)
1919  {
1920  for($order = 0; $order < $this->gaps[$gap_id]->getItemCount(); $order++)
1921  {
1922  $answer = $this->gaps[$gap_id]->getItem($order);
1923  if($value["value"] == $answer->getOrder())
1924  {
1925  $answerpoints = $answer->getPoints();
1926  if(!$this->getIdenticalScoring())
1927  {
1928  // check if the same solution value was already entered
1929  if((in_array($answer->getAnswertext(), $solution_values_select)) && ($answerpoints > 0))
1930  {
1931  $answerpoints = 0;
1932  }
1933  }
1934  $points += $answerpoints;
1935  $detailed[$gap_id] = array("points" => $answerpoints, "best" => ($this->getMaximumGapPoints($gap_id) == $answerpoints) ? TRUE : FALSE, "positive" => ($answerpoints > 0) ? TRUE : FALSE);
1936  array_push($solution_values_select, $answer->getAnswertext());
1937  }
1938  }
1939  }
1940  break;
1941  }
1942  }
1943  }
1944 
1945  return $points;
1946  }
1947 
1949  {
1950  $userSolution = array();
1951 
1952  foreach($previewSession->getParticipantsSolution() as $key => $val)
1953  {
1954  $userSolution[] = array('gap_id' => $key, 'value' => $val);
1955  }
1956 
1957  return $this->calculateReachedPointsForSolution($userSolution);
1958  }
1959 }
getId()
Gets the id of the assQuestion object.
toJSON()
Returns a JSON representation of the question.
getGapCount()
Returns the number of gaps.
static _getOriginalId($question_id)
Returns the original id of a question.
formatSAQuestion($a_q)
Format self assessment question.
const TEXTGAP_RATING_LEVENSHTEIN5
Class for cloze question numeric answers.
$size
Definition: RandomTest.php:79
getMaximumGapPoints($gap_index)
Returns the maximum points for a gap.
createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle="")
getQuestionType()
Returns the question type of the question.
Class iQuestionCondition.
$_POST['username']
Definition: cron.php:12
setEndTag($end_tag="[/gap]")
Sets the end tag of a cloze gap.
clearGapAnswers()
Removes all answers from the gaps.
Class for cloze tests.
getAdditionalTableName()
Returns the name of the additional question data table in the database.
saveAnswerSpecificDataToDb()
Save all gaps to the database.
getAnswerTableName()
Returns the name of the answer table in the database.
$result
const TEXTGAP_RATING_LEVENSHTEIN2
const TEXTGAP_RATING_LEVENSHTEIN1
& getSolutionValues($active_id, $pass=NULL)
Loads solutions of a given user from the database an returns it.
Abstract basic class which is to be extended by the concrete assessment question type classes...
_getPass($active_id)
Retrieves the actual pass of a given user for a given test.
const CLOZE_TEXT
Cloze question constants.
setGapSize($gap_index, $order, $size)
getRTETextWithMediaObjects()
Collects all text in the question which could contain media objects which were created with the Rich ...
_convert_text($a_text, $a_target="has been removed")
calculateCombinationResult($user_result)
getOperators($expression)
Get all available operations for a specific question.
getMaximumPoints()
Returns the maximum points, a learner can reach answering the question.
setId($id=-1)
Sets the id of the assQuestion object.
getSolutionMaxPass($active_id)
Returns the maximum pass a users question solution.
setExportDetailsXLS(&$worksheet, $startrow, $active_id, $pass, &$format_title, &$format_bold)
Creates an Excel worksheet for the detailed cumulated results of this question.
setEstimatedWorkingTime($hour=0, $min=0, $sec=0)
Sets the estimated working time of a question from given hour, minute and second. ...
copyGapCombination($orgID, $newID)
getGap($gap_index=0)
Returns the gap at a given index.
setGapAnswerPoints($gap_index, $order, $points)
Sets the points of a gap with a given index and an answer with a given order.
getTextgapRating()
Returns the rating option for text gaps.
Class for cloze question gaps.
saveToDb($original_id="")
Saves a assClozeTest object to a database.
static strToLower($a_string)
Definition: class.ilStr.php:89
setClozeTextValue($cloze_text="")
getUserQuestionResult($active_id, $pass)
Get the user solution for a question by active_id and the test pass.
checkForValidFormula($value)
setNrOfTries($a_nr_of_tries)
_enabledAssessmentLogging()
check wether assessment logging is enabled or not
setAdditionalContentEditingMode($additinalContentEditingMode)
setter for additional content editing mode for this question
static _replaceMediaObjectImageSrc($a_text, $a_direction=0, $nic=IL_INST_ID)
replaces image source from mob image urls with the mob id or replaces mob id with the correct image s...
createGapsFromQuestiontext()
Create gap entries by parsing the question text.
getObjId()
Get the object id of the container object.
getShuffle()
Gets the shuffle flag.
getNumericgapPoints($a_original, $a_entered, $max_points, $lowerBound, $upperBound)
Returns the points for a text gap and compares the given solution with the entered solution using the...
getStartTag()
Returns the start tag of a cloze gap.
getTextgapPoints($a_original, $a_entered, $max_points)
Returns the points for a text gap and compares the given solution with the entered solution using the...
setGapType($gap_index, $gap_type)
Set the type of a gap with a given index.
setGapCombinationsExists($value)
getGaps()
Returns the array of gaps.
calculateReachedPoints($active_id, $pass=NULL, $returndetails=FALSE)
Returns the points, a learner has reached answering the question.
setAuthor($author="")
Sets the authors name of the assQuestion object.
duplicate($for_test=true, $title="", $author="", $owner="", $testObjId=null)
Duplicates an assClozeTest.
const CLOZE_SELECT
getAuthor()
Gets the authors name of the assQuestion object.
const TEXTGAP_RATING_LEVENSHTEIN3
$mobs
setGapAnswerLowerBound($gap_index, $order, $bound)
Sets the lower bound of a gap with a given index and an answer with a given order.
Class ilUserQuestionResult.
setFixedTextLength($a_text_len)
Sets a fixed text length for all text fields in the cloze question.
copyObject($target_questionpool_id, $title="")
Copies an assClozeTest object.
const TEXTGAP_RATING_CASESENSITIVE
Interface ilObjAnswerScoringAdjustable.
prepareTextareaOutput($txt_output, $prepare_for_latex_output=FALSE)
Prepares a string for a text area output in tests.
getQuestion()
Gets the question string of the question object.
addGapAtIndex($gap, $index)
Adds a ClozeGap object at a given index.
static stripSlashes($a_str, $a_strip_html=true, $a_allow="")
strip slashes if magic qoutes is enabled
setGapAnswerUpperBound($gap_index, $order, $bound)
Sets the upper bound of a gap with a given index and an answer with a given order.
saveClozeTextGapRecordToDb($next_id, $key, $item, $gap)
Saves a gap-item record.
saveAdditionalQuestionDataToDb()
Saves the data for the additional data table.
addGapAnswer($gap_index, $order, $answer)
Sets the answer text of a gap with a given index.
setGapShuffle($gap_index=0, $shuffle=1)
Sets the shuffle state of a gap with a given index.
setClozeText($cloze_text="")
Evaluates the text gap solutions from the cloze text.
cleanQuestiontext($text)
Cleans cloze question text to remove attributes or tags from older ILIAS versions.
getExpressionTypes()
Get all available expression types for a specific question.
_getLogLanguage()
retrieve the log language for assessment logging
flushGaps()
Deletes all gaps without changing the cloze text.
_getMobsOfObject($a_type, $a_id, $a_usage_hist_nr=0, $a_lang="-")
get mobs of object
setPoints($a_points)
Sets the maximum available points for the question.
saveQuestionDataToDb($original_id="")
calculateReachedPointsFromPreviewSession(ilAssQuestionPreviewSession $previewSession)
saveClozeNumericGapRecordToDb($next_id, $key, $item, $gap)
Saves a gap-item record.
deleteGap($gap_index)
Deletes a gap with a given index.
updateClozeTextFromGaps()
Updates the gap parameters in the cloze text from the form input.
setTextgapRating($a_textgap_rating)
Sets the rating option for text gaps.
global $ilUser
Definition: imgupload.php:15
setQuestion($question="")
Sets the question string of the question object.
Interface ilObjQuestionScoringAdjustable.
getEndTag()
Returns the end tag of a cloze gap.
setStartTag($start_tag="[gap]")
Sets the start tag of a cloze gap.
addGapText($gap_index)
Adds a new answer text value to a text gap with a given index.
deleteAnswerText($gap_index, $answer_index)
Deletes the answer text of a gap with a given index and an answer with a given order.
getFixedTextLength()
Gets the fixed text length for all text fields in the cloze question.
const TEXTGAP_RATING_LEVENSHTEIN4
global $ilDB
setOriginalId($original_id)
saveClozeSelectGapRecordToDb($next_id, $key, $item, $gap)
Saves a gap-item record.
getClozeText()
Returns the cloze text.
reworkWorkingData($active_id, $pass, $obligationsAnswered)
Reworks the allready saved working data if neccessary.
logAction($logtext="", $active_id="", $question_id="")
Logs an action into the Test&Assessment log.
getTitle()
Gets the title string of the assQuestion object.
__construct( $title="", $comment="", $author="", $owner=-1, $question="")
assClozeTest constructor
loadFromDb($question_id)
Loads a assClozeTest object from a database.
const CLOZE_NUMERIC
isComplete()
Returns TRUE, if a cloze test is complete for use.
saveWorkingData($active_id, $pass=NULL)
Saves the learners input of the question to the database.
getIdenticalScoring()
Returns the identical scoring status of the question.
setTitle($title="")
Sets the title string of the assQuestion object.
setObjId($obj_id=0)
Set the object id of the container object.
setIdenticalScoring($a_identical_scoring)
Sets the identical scoring option for cloze questions.
setComment($comment="")
Sets the comment string of the assQuestion object.
getAvailableAnswerOptions($index=null)
If index is null, the function returns an array with all anwser options Else it returns the specific ...
saveClozeGapItemsToDb($gap, $key)
Save all items belonging to one cloze gap to the db.
calculateReachedPointsForSolution($user_result, &$detailed=null)
setOwner($owner="")
Sets the creator/owner ID of the assQuestion object.
const TEXTGAP_RATING_CASEINSENSITIVE