4 require_once
'./Modules/TestQuestionPool/classes/class.assQuestion.php';
5 require_once
'./Modules/Test/classes/inc.AssessmentConstants.php';
6 require_once
'./Modules/TestQuestionPool/interfaces/interface.ilObjQuestionScoringAdjustable.php';
7 require_once
'./Modules/TestQuestionPool/interfaces/interface.ilObjAnswerScoringAdjustable.php';
101 $this->start_tag =
"[gap]";
102 $this->end_tag =
"[/gap]";
103 $this->gaps = array();
105 $this->fixedTextLength =
"";
106 $this->identical_scoring = 1;
136 $text = preg_replace(
"/\[gap[^\]]*?\]/",
"[gap]", $text);
137 $text = preg_replace(
"/<gap([^>]*?)>/",
"[gap]", $text);
138 $text = str_replace(
"</gap>",
"[/gap]", $text);
157 $data = $ilDB->fetchAssoc(
$result);
158 $this->
setId($question_id);
171 include_once(
"./Services/RTE/classes/class.ilRTE.php");
174 $this->
setEstimatedWorkingTime(substr($data[
"working_time"], 0, 2), substr($data[
"working_time"], 3, 2), substr($data[
"working_time"], 6, 2));
185 include_once
"./Modules/TestQuestionPool/classes/class.assAnswerCloze.php";
186 include_once
"./Modules/TestQuestionPool/classes/class.assClozeGap.php";
187 $result = $ilDB->queryF(
"SELECT * FROM qpl_a_cloze WHERE question_fi = %s ORDER BY gap_id, aorder ASC",
193 $this->gaps = array();
194 while ($data = $ilDB->fetchAssoc(
$result))
196 switch ($data[
"cloze_type"])
199 if (!array_key_exists($data[
"gap_id"], $this->gaps))
208 $this->gaps[$data[
"gap_id"]]->addItem($answer);
211 if (!array_key_exists($data[
"gap_id"], $this->gaps))
214 $this->gaps[$data[
"gap_id"]]->setShuffle($data[
"shuffle"]);
221 $this->gaps[$data[
"gap_id"]]->addItem($answer);
224 if (!array_key_exists($data[
"gap_id"], $this->gaps))
233 $answer->setLowerBound($data[
"lowerlimit"]);
234 $answer->setUpperBound($data[
"upperlimit"]);
235 $this->gaps[$data[
"gap_id"]]->addItem($answer);
244 #region Save question to db
271 $ilDB->manipulateF(
"DELETE FROM qpl_a_cloze WHERE question_fi = %s",
273 array( $this->
getId() )
276 foreach ($this->gaps as $key => $gap)
293 array( $this->
getId() )
297 .
" (question_fi, textgap_rating, identical_scoring, fixed_textlen) VALUES (%s, %s, %s, %s)",
322 foreach ($gap->getItems() as $item)
325 $next_id = $ilDB->nextId(
'qpl_a_cloze' );
326 switch ($gap->getType())
352 $ilDB->manipulateF(
"INSERT INTO qpl_a_cloze (answer_id, question_fi, gap_id, answertext, points, aorder, cloze_type) VALUES (%s, %s, %s, %s, %s, %s, %s)",
366 strlen( $item->getAnswertext() ) ? $item->getAnswertext() :
"",
385 $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)",
400 strlen( $item->getAnswertext() ) ? $item->getAnswertext() :
"",
404 ($gap->getShuffle()) ?
"1" :
"0"
421 include_once
"./Services/Math/classes/class.EvalMath.php";
423 $eval->suppress_errors = TRUE;
427 $answerText = strlen($item->getAnswertext()) ? (
float)$item->getAnswertext() : 0;
430 $eval->e( $item->getLowerBound() !== FALSE ) && strlen( $item->getLowerBound() ) ?
431 $item->getLowerBound() : $item->getAnswertext()
435 $eval->e( $item->getUpperBound() !== FALSE ) && strlen( $item->getUpperBound() ) ?
436 $item->getUpperBound() : $item->getAnswertext()
441 $ilDB->manipulateF(
"INSERT INTO qpl_a_cloze (answer_id, question_fi, gap_id, answertext, points, aorder, cloze_type, lowerlimit, upperlimit) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)",
469 #endregion Save question to db
491 $this->gaps = array();
505 $this->gaps = array();
507 $this->question = $cloze_text;
579 include_once
"./Modules/TestQuestionPool/classes/class.assClozeGap.php";
580 include_once
"./Modules/TestQuestionPool/classes/class.assAnswerCloze.php";
581 $search_pattern =
"|\[gap\](.*?)\[/gap\]|i";
582 preg_match_all($search_pattern, $this->
getClozeText(), $found);
583 $this->gaps = array();
584 if (count($found[0]))
586 foreach ($found[1] as $gap_index => $answers)
590 $textparams = preg_split(
"/(?<!\\\\),/", $answers);
591 foreach ($textparams as $key => $value)
594 $gap->addItem($answer);
596 $this->gaps[$gap_index] = $gap;
608 if (array_key_exists($gap_index, $this->gaps))
610 $this->gaps[$gap_index]->setType($gap_type);
625 if (array_key_exists($gap_index, $this->gaps))
627 $this->gaps[$gap_index]->setShuffle(
$shuffle);
639 foreach ($this->gaps as $gap_index => $gap)
641 $this->gaps[$gap_index]->clearItems();
654 if (is_array($this->gaps))
656 return count($this->gaps);
676 if (array_key_exists($gap_index, $this->gaps))
681 $answer = str_replace(
",",
".", $answer);
683 $this->gaps[$gap_index]->addItem(
new assAnswerCloze($answer, 0, $order));
697 if (array_key_exists($gap_index, $this->gaps))
699 return $this->gaps[$gap_index];
719 if (array_key_exists($gap_index, $this->gaps))
721 $this->gaps[$gap_index]->setItemPoints($order,
$points);
735 if (array_key_exists($gap_index, $this->gaps))
737 include_once
"./Modules/TestQuestionPool/classes/class.assAnswerCloze.php";
741 $this->gaps[$gap_index]->getItemCount()
743 $this->gaps[$gap_index]->addItem($answer);
757 $this->gaps[$index] = $gap;
772 if (array_key_exists($gap_index, $this->gaps))
774 $this->gaps[$gap_index]->setItemLowerBound($order, $bound);
790 if (array_key_exists($gap_index, $this->gaps))
792 $this->gaps[$gap_index]->setItemUpperBound($order, $bound);
805 foreach ($this->gaps as $gap_index => $gap)
810 foreach ($gap->getItems() as $item)
812 if ($item->getPoints() > $gap_max_points)
814 $gap_max_points = $item->getPoints();
822 foreach ($gap->getItems() as $item)
824 if ($item->getPoints() > $srpoints)
826 $srpoints = $item->getPoints();
834 foreach ($gap->getItems() as $item)
836 if ($item->getPoints() > $numpoints)
838 $numpoints = $item->getPoints();
860 $this_id = $this->
getId();
864 include_once (
"./Modules/TestQuestionPool/classes/class.assQuestion.php");
868 if( (
int)$testObjId > 0 )
870 $clone->setObjId($testObjId);
895 $clone->copyPageOfQuestion($this_id);
897 $clone->copyXHTMLMediaObjectsOfQuestion($this_id);
899 $clone->onDuplicate($thisObjId, $this_id, $clone->getObjId(), $clone->getId());
901 return $clone->getId();
911 if ($this->
getId() <= 0)
917 $thisId = $this->
getId();
921 include_once (
"./Modules/TestQuestionPool/classes/class.assQuestion.php");
924 $clone->setObjId($target_questionpool_id);
936 $clone->onCopy($thisObjId, $thisId, $clone->getObjId(), $clone->getId());
938 return $clone->getId();
949 include_once (
"./Modules/TestQuestionPool/classes/class.assQuestion.php");
952 $sourceParentId = $this->
getObjId();
958 $clone->setObjId($targetParentId);
960 if ($targetQuestionTitle)
962 $clone->setTitle($targetQuestionTitle);
967 $clone->copyPageOfQuestion($sourceQuestionId);
969 $clone->copyXHTMLMediaObjectsOfQuestion($sourceQuestionId);
971 $clone->onCopy($sourceParentId, $sourceQuestionId, $clone->getObjId(), $clone->getId());
984 foreach ($this->
getGaps() as $gap_index => $gap)
987 foreach ($gap->getItemsRaw() as $item)
989 array_push($answers, str_replace(
",",
"\\,", $item->getAnswerText()));
991 $output = preg_replace(
"/\[gap\].*?\[\/gap\]/",
"[_gap]" . $this->
prepareTextareaOutput(join(
",", $answers),
true) .
"[/_gap]", $output, 1);
993 $output = str_replace(
"_gap]",
"gap]", $output);
994 $this->question = $output;
1008 if (array_key_exists($gap_index, $this->gaps))
1010 if ($this->gaps[$gap_index]->getItemCount() == 1)
1018 $this->gaps[$gap_index]->deleteItem($answer_index);
1034 if (array_key_exists($gap_index, $this->gaps))
1037 foreach ($this->
getGaps() as $replace_gap_index => $gap)
1040 foreach ($gap->getItemsRaw() as $item)
1042 array_push($answers, str_replace(
",",
"\\,", $item->getAnswerText()));
1044 if ($replace_gap_index == $gap_index)
1046 $output = preg_replace(
"/\[gap\].*?\[\/gap\]/",
"", $output, 1);
1050 $output = preg_replace(
"/\[gap\].*?\[\/gap\]/",
"[_gap]" . join(
",", $answers) .
"[/_gap]", $output, 1);
1053 $output = str_replace(
"_gap]",
"gap]", $output);
1054 $this->question = $output;
1055 unset($this->gaps[$gap_index]);
1056 $this->gaps = array_values($this->gaps);
1071 include_once
"./Services/Utilities/classes/class.ilStr.php";
1080 if (strcmp($a_original, $a_entered) == 0)
$result = $max_points;
1083 if (levenshtein($a_original, $a_entered) <= 1)
$result = $max_points;
1086 if (levenshtein($a_original, $a_entered) <= 2)
$result = $max_points;
1089 if (levenshtein($a_original, $a_entered) <= 3)
$result = $max_points;
1092 if (levenshtein($a_original, $a_entered) <= 4)
$result = $max_points;
1095 if (levenshtein($a_original, $a_entered) <= 5)
$result = $max_points;
1112 if( !is_numeric($a_entered) )
1117 include_once
"./Services/Math/classes/class.EvalMath.php";
1119 $eval->suppress_errors = TRUE;
1121 if (($eval->e($lowerBound) !== FALSE) && ($eval->e($upperBound) !== FALSE))
1123 if (($eval->e($a_entered) >= $eval->e($lowerBound)) && ($eval->e($a_entered) <= $eval->e($upperBound)))
$result = $max_points;
1125 else if ($eval->e($lowerBound) !== FALSE)
1127 if (($eval->e($a_entered) >= $eval->e($lowerBound)) && ($eval->e($a_entered) <= $eval->e($a_original)))
$result = $max_points;
1129 else if ($eval->e($upperBound) !== FALSE)
1131 if (($eval->e($a_entered) >= $eval->e($a_original)) && ($eval->e($a_entered) <= $eval->e($upperBound)))
$result = $max_points;
1135 if ($eval->e($a_entered) == $eval->e($a_original))
$result = $max_points;
1154 $found_value1 = array();
1155 $found_value2 = array();
1156 $detailed = array();
1161 $result = $ilDB->queryF(
"SELECT * FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
1173 $user_result = array();
1174 while ($data = $ilDB->fetchAssoc(
$result))
1176 if (strcmp($data[
"value2"],
"") != 0)
1178 $user_result[$data[
"value1"]] = array(
1179 "gap_id" => $data[
"value1"],
1180 "value" => $data[
"value2"]
1185 ksort($user_result);
1189 $solution_values_text = array();
1190 $solution_values_select = array();
1191 $solution_values_numeric = array();
1192 foreach ($user_result as $gap_id => $value)
1194 if (array_key_exists($gap_id, $this->gaps))
1196 switch ($this->gaps[$gap_id]->getType())
1200 for ($order = 0; $order < $this->gaps[$gap_id]->getItemCount(); $order++)
1202 $answer = $this->gaps[$gap_id]->getItem($order);
1203 $gotpoints = $this->
getTextgapPoints($answer->getAnswertext(), $value[
"value"], $answer->getPoints());
1204 if ($gotpoints > $gappoints) $gappoints = $gotpoints;
1209 if ((in_array($value[
"value"], $solution_values_text)) && ($gappoints > 0))
1215 $detailed[$gap_id] = array(
"points" =>$gappoints,
"best" => ($this->
getMaximumGapPoints($gap_id) == $gappoints) ? TRUE : FALSE,
"positive" => ($gappoints > 0) ? TRUE : FALSE);
1216 array_push($solution_values_text, $value[
"value"]);
1220 for ($order = 0; $order < $this->gaps[$gap_id]->getItemCount(); $order++)
1222 $answer = $this->gaps[$gap_id]->getItem($order);
1223 $gotpoints = $this->
getNumericgapPoints($answer->getAnswertext(), $value[
"value"], $answer->getPoints(), $answer->getLowerBound(), $answer->getUpperBound());
1224 if ($gotpoints > $gappoints) $gappoints = $gotpoints;
1229 include_once
"./Services/Math/classes/class.EvalMath.php";
1231 $eval->suppress_errors = TRUE;
1232 $found_value = FALSE;
1233 foreach ($solution_values_numeric as $solval)
1235 if ($eval->e($solval) == $eval->e($value[
"value"]))
1237 $found_value = TRUE;
1240 if ($found_value && ($gappoints > 0))
1246 $detailed[$gap_id] = array(
"points" =>$gappoints,
"best" => ($this->
getMaximumGapPoints($gap_id) == $gappoints) ? TRUE : FALSE,
"positive" => ($gappoints > 0) ? TRUE : FALSE);
1247 array_push($solution_values_numeric, $value[
"value"]);
1250 if ($value[
"value"] >= 0)
1252 for ($order = 0; $order < $this->gaps[$gap_id]->getItemCount(); $order++)
1254 $answer = $this->gaps[$gap_id]->getItem($order);
1255 if ($value[
"value"] == $answer->getOrder())
1257 $answerpoints = $answer->getPoints();
1261 if ((in_array($answer->getAnswertext(), $solution_values_select)) && ($answerpoints > 0))
1267 $detailed[$gap_id] = array(
"points" =>$answerpoints,
"best" => ($this->
getMaximumGapPoints($gap_id) == $answerpoints) ? TRUE : FALSE,
"positive" => ($answerpoints > 0) ? TRUE : FALSE);
1268 array_push($solution_values_select, $answer->getAnswertext());
1300 include_once
"./Modules/Test/classes/class.ilObjTest.php";
1306 $affectedRows = $ilDB->manipulateF(
"DELETE FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
1319 $entered_values = 0;
1320 foreach (
$_POST as $key => $value)
1322 if (preg_match(
"/^gap_(\d+)/", $key, $matches))
1327 $gap = $this->
getGap($matches[1]);
1328 if (is_object($gap))
1330 if (!(($gap->getType() ==
CLOZE_SELECT) && ($value == -1)))
1334 $value = str_replace(
",",
".", $value);
1336 $next_id = $ilDB->nextId(
"tst_solutions");
1337 $affectedRows = $ilDB->insert(
"tst_solutions", array(
1338 "solution_id" => array(
"integer", $next_id),
1339 "active_fi" => array(
"integer", $active_id),
1340 "question_fi" => array(
"integer", $this->
getId()),
1341 "value1" => array(
"clob", trim($matches[1])),
1342 "value2" => array(
"clob", trim($value)),
1343 "pass" => array(
"integer",
$pass),
1344 "tstamp" => array(
"integer", time())
1355 if ($entered_values)
1357 include_once (
"./Modules/Test/classes/class.ilObjAssessmentFolder.php");
1365 include_once (
"./Modules/Test/classes/class.ilObjAssessmentFolder.php");
1396 return "assClozeTest";
1420 switch ($a_textgap_rating)
1429 $this->textgap_rating = $a_textgap_rating;
1446 return ($this->identical_scoring) ? 1 : 0;
1458 $this->identical_scoring = ($a_identical_scoring) ? 1 : 0;
1469 return "qpl_qst_cloze";
1480 return "qpl_a_cloze";
1491 $this->fixedTextLength = $a_text_len;
1516 if (array_key_exists($gap_index, $this->gaps))
1518 $gap =& $this->gaps[$gap_index];
1520 $gap_max_points = 0;
1521 foreach ($gap->getItems() as $answer)
1523 if ($answer->getPoints() > $gap_max_points)
1525 $gap_max_points = $answer->getPoints();
1556 include_once (
"./Services/Excel/classes/class.ilExcelUtils.php");
1561 foreach ($this->
getGaps() as $gap_index => $gap)
1565 foreach ($solution as $solutionvalue)
1567 if ($gap_index == $solutionvalue[
"value1"])
1569 switch ($gap->getType())
1572 $worksheet->writeString($startrow + $i, 1, $gap->getItem($solutionvalue[
"value2"])->getAnswertext());
1576 $worksheet->writeString($startrow + $i, 1, $solutionvalue[
"value2"]);
1583 return $startrow + $i + 1;
1591 include_once(
"./Services/RTE/classes/class.ilRTE.php");
1600 "onenotcorrect" => $this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(),
false),
1601 "allcorrect" => $this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(),
true)
1604 foreach ($this->
getGaps() as $key => $gap)
1607 foreach ($gap->getItems() as $item)
1610 $jitem[
'points'] = $item->getPoints();
1612 $jitem[
'order'] = $item->getOrder();
1615 $jitem[
'lowerbound'] = $item->getLowerBound();
1616 $jitem[
'upperbound'] = $item->getUpperBound();
1620 $jitem[
'value'] = trim($jitem[
'value']);
1622 array_push($items, $jitem);
1624 $jgap[
'shuffle'] = $gap->getShuffle();
1625 $jgap[
'type'] = $gap->getType();
1626 $jgap[
'item'] = $items;
1627 array_push(
$gaps, $jgap);