00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
00025 include_once "./Modules/Test/classes/inc.AssessmentConstants.php";
00026
00036 class assClozeTest extends assQuestion
00037 {
00045 var $gaps;
00046
00054 var $start_tag;
00055
00063 var $end_tag;
00064
00075 var $textgap_rating;
00076
00086 var $identical_scoring;
00087
00093 var $fixedTextLength;
00094
00107 function assClozeTest(
00108 $title = "",
00109 $comment = "",
00110 $author = "",
00111 $owner = -1,
00112 $cloze_text = ""
00113 )
00114 {
00115 $this->start_tag = "[gap]";
00116 $this->end_tag = "[/gap]";
00117 $this->assQuestion($title, $comment, $author, $owner);
00118 $this->gaps = array();
00119 $this->setClozeText($cloze_text);
00120 $this->fixedTextLength = "";
00121 $this->identical_scoring = 1;
00122 }
00123
00132 function isComplete()
00133 {
00134 if (($this->title) and ($this->author) and ($this->getClozeText()) and (count($this->gaps)) and ($this->getMaximumPoints() > 0))
00135 {
00136 return true;
00137 }
00138 else
00139 {
00140 return false;
00141 }
00142 }
00143
00153 function cleanQuestiontext($text)
00154 {
00155 $text = preg_replace("/\[gap[^\]]*?\]/", "[gap]", $text);
00156 $text = preg_replace("/<gap([^>]*?)>/", "[gap]", $text);
00157 $text = str_replace("</gap>", "[/gap]", $text);
00158 return $text;
00159 }
00160
00170 function loadFromDb($question_id)
00171 {
00172 global $ilDB;
00173 $query = sprintf("SELECT qpl_questions.*, %s.* FROM qpl_questions, %s WHERE question_id = %s AND qpl_questions.question_id = %s.question_fi",
00174 $this->getAdditionalTableName(),
00175 $this->getAdditionalTableName(),
00176 $ilDB->quote($question_id),
00177 $this->getAdditionalTableName()
00178 );
00179 $result = $ilDB->query($query);
00180 if (strcmp(strtolower(get_class($result)), db_result) == 0)
00181 {
00182 if ($result->numRows() == 1)
00183 {
00184 $data = $result->fetchRow(DB_FETCHMODE_OBJECT);
00185 $this->id = $question_id;
00186 $this->obj_id = $data->obj_fi;
00187 $this->title = $data->title;
00188 $this->comment = $data->comment;
00189 $this->solution_hint = $data->solution_hint;
00190 $this->original_id = $data->original_id;
00191 $this->author = $data->author;
00192 $this->points = $data->points;
00193 $this->owner = $data->owner;
00194 $this->question = $this->cleanQuestiontext($data->question_text);
00195 $this->setFixedTextLength($data->fixed_textlen);
00196 $this->setIdenticalScoring($data->identical_scoring);
00197
00198 include_once("./Services/RTE/classes/class.ilRTE.php");
00199 $this->question = ilRTE::_replaceMediaObjectImageSrc($this->question, 1);
00200 $this->setTextgapRating($data->textgap_rating);
00201 $this->setEstimatedWorkingTime(substr($data->working_time, 0, 2), substr($data->working_time, 3, 2), substr($data->working_time, 6, 2));
00202 }
00203
00204
00205 include_once "./Modules/TestQuestionPool/classes/class.assAnswerCloze.php";
00206 include_once "./Modules/TestQuestionPool/classes/class.assClozeGap.php";
00207 $query = sprintf("SELECT * FROM qpl_answer_cloze WHERE question_fi = %s ORDER BY gap_id, aorder ASC",
00208 $ilDB->quote($question_id)
00209 );
00210 $result = $ilDB->query($query);
00211 if (strcmp(strtolower(get_class($result)), db_result) == 0)
00212 {
00213 $this->gaps = array();
00214 while ($data = $result->fetchRow(DB_FETCHMODE_ASSOC))
00215 {
00216 switch ($data["cloze_type"])
00217 {
00218 case CLOZE_TEXT:
00219 if (!array_key_exists($data["gap_id"], $this->gaps))
00220 {
00221 $this->gaps[$data["gap_id"]] = new assClozeGap(CLOZE_TEXT);
00222 }
00223 $answer = new assAnswerCloze(
00224 $data["answertext"],
00225 $data["points"],
00226 $data["aorder"]
00227 );
00228 $this->gaps[$data["gap_id"]]->addItem($answer);
00229 break;
00230 case CLOZE_SELECT:
00231 if (!array_key_exists($data["gap_id"], $this->gaps))
00232 {
00233 $this->gaps[$data["gap_id"]] = new assClozeGap(CLOZE_SELECT);
00234 $this->gaps[$data["gap_id"]]->setShuffle($data["shuffle"]);
00235 }
00236 $answer = new assAnswerCloze(
00237 $data["answertext"],
00238 $data["points"],
00239 $data["aorder"]
00240 );
00241 $this->gaps[$data["gap_id"]]->addItem($answer);
00242 break;
00243 case CLOZE_NUMERIC:
00244 if (!array_key_exists($data["gap_id"], $this->gaps))
00245 {
00246 $this->gaps[$data["gap_id"]] = new assClozeGap(CLOZE_NUMERIC);
00247 }
00248 $answer = new assAnswerCloze(
00249 $data["answertext"],
00250 $data["points"],
00251 $data["aorder"]
00252 );
00253 $answer->setLowerBound($data["lowerlimit"]);
00254 $answer->setUpperBound($data["upperlimit"]);
00255 $this->gaps[$data["gap_id"]]->addItem($answer);
00256 break;
00257 }
00258 }
00259 }
00260 }
00261 parent::loadFromDb($question_id);
00262 }
00263
00272 function saveToDb($original_id = "")
00273 {
00274 global $ilDB;
00275
00276 include_once "./Services/Math/classes/class.EvalMath.php";
00277 $eval = new EvalMath();
00278 $eval->suppress_errors = TRUE;
00279 $complete = 0;
00280 if ($this->isComplete())
00281 {
00282 $complete = 1;
00283 }
00284
00285 $estw_time = $this->getEstimatedWorkingTime();
00286 $estw_time = sprintf("%02d:%02d:%02d", $estw_time['h'], $estw_time['m'], $estw_time['s']);
00287 $original_id = $original_id ? $ilDB->quote($original_id) : "NULL";
00288
00289
00290 include_once("./Services/RTE/classes/class.ilRTE.php");
00291 if ($this->id == -1)
00292 {
00293 $now = getdate();
00294 $created = sprintf("%04d%02d%02d%02d%02d%02d", $now['year'], $now['mon'], $now['mday'], $now['hours'], $now['minutes'], $now['seconds']);
00295 $query = sprintf("INSERT INTO qpl_questions (question_id, question_type_fi, obj_fi, title, comment, points, author, " .
00296 "owner, question_text, working_time, complete, created, original_id, TIMESTAMP) " .
00297 "VALUES (NULL, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, NULL)",
00298 $ilDB->quote($this->getQuestionTypeID() . ""),
00299 $ilDB->quote($this->obj_id . ""),
00300 $ilDB->quote($this->title . ""),
00301 $ilDB->quote($this->comment . ""),
00302 $ilDB->quote($this->getMaximumPoints() . ""),
00303 $ilDB->quote($this->author . ""),
00304 $ilDB->quote($this->owner . ""),
00305 $ilDB->quote(ilRTE::_replaceMediaObjectImageSrc($this->getClozeText(), 0)),
00306 $ilDB->quote($estw_time . ""),
00307 $ilDB->quote($complete . ""),
00308 $ilDB->quote($created . ""),
00309 $original_id
00310 );
00311 $result = $ilDB->query($query);
00312 if ($result == DB_OK)
00313 {
00314 $this->id = $ilDB->getLastInsertId();
00315 $query = sprintf("INSERT INTO %s (question_fi, textgap_rating, identical_scoring, fixed_textlen) VALUES (%s, %s, %s, %s)",
00316 $this->getAdditionalTableName(),
00317 $ilDB->quote($this->id . ""),
00318 $ilDB->quote($this->textgap_rating . ""),
00319 $ilDB->quote($this->getIdenticalScoring() . ""),
00320 $this->getFixedTextLength() ? $ilDB->quote($this->getFixedTextLength()) : "NULL"
00321 );
00322 $ilDB->query($query);
00323
00324
00325 $this->createPageObject();
00326
00327 if ($this->getTestId() > 0)
00328 {
00329 $this->insertIntoTest($this->getTestId());
00330 }
00331 }
00332 }
00333 else
00334 {
00335 $query = sprintf("UPDATE qpl_questions SET obj_fi = %s, title = %s, comment = %s, points = %s, author = %s, " .
00336 "question_text = %s, working_time = %s, complete = %s WHERE question_id = %s",
00337 $ilDB->quote($this->obj_id. ""),
00338 $ilDB->quote($this->title . ""),
00339 $ilDB->quote($this->comment . ""),
00340 $ilDB->quote($this->getMaximumPoints() . ""),
00341 $ilDB->quote($this->author . ""),
00342 $ilDB->quote(ilRTE::_replaceMediaObjectImageSrc($this->getClozeText(), 0)),
00343 $ilDB->quote($estw_time . ""),
00344 $ilDB->quote($complete . ""),
00345 $ilDB->quote($this->id . "")
00346 );
00347 $result = $ilDB->query($query);
00348 $query = sprintf("UPDATE %s SET textgap_rating = %s, fixed_textlen = %s, identical_scoring = %s WHERE question_fi = %s",
00349 $this->getAdditionalTableName(),
00350 $ilDB->quote($this->textgap_rating . ""),
00351 $this->getFixedTextLength() ? $ilDB->quote($this->getFixedTextLength()) : "NULL",
00352 $ilDB->quote($this->getIdenticalScoring() . ""),
00353 $ilDB->quote($this->id . "")
00354 );
00355 $result = $ilDB->query($query);
00356 }
00357
00358 if ($result == DB_OK)
00359 {
00360
00361 $query = sprintf("DELETE FROM qpl_answer_cloze WHERE question_fi = %s",
00362 $ilDB->quote($this->id . "")
00363 );
00364 $result = $ilDB->query($query);
00365 foreach ($this->gaps as $key => $gap)
00366 {
00367 foreach ($gap->getItems() as $item)
00368 {
00369 $query = "";
00370 switch ($gap->getType())
00371 {
00372 case CLOZE_TEXT:
00373 $query = sprintf("INSERT INTO qpl_answer_cloze (answer_id, question_fi, gap_id, answertext, points, aorder, cloze_type) VALUES (NULL, %s, %s, %s, %s, %s, %s)",
00374 $ilDB->quote($this->getId()),
00375 $ilDB->quote($key . ""),
00376 $ilDB->quote($item->getAnswertext() . ""),
00377 $ilDB->quote($item->getPoints() . ""),
00378 $ilDB->quote($item->getOrder() . ""),
00379 $ilDB->quote($gap->getType() . "")
00380 );
00381 break;
00382 case CLOZE_SELECT:
00383 $query = sprintf("INSERT INTO qpl_answer_cloze (answer_id, question_fi, gap_id, answertext, points, aorder, cloze_type, shuffle) VALUES (NULL, %s, %s, %s, %s, %s, %s, %s)",
00384 $ilDB->quote($this->getId()),
00385 $ilDB->quote($key . ""),
00386 $ilDB->quote($item->getAnswertext() . ""),
00387 $ilDB->quote($item->getPoints() . ""),
00388 $ilDB->quote($item->getOrder() . ""),
00389 $ilDB->quote($gap->getType() . ""),
00390 $ilDB->quote($gap->getShuffle() ? "1" : "0")
00391 );
00392 break;
00393 case CLOZE_NUMERIC:
00394 $query = sprintf("INSERT INTO qpl_answer_cloze (answer_id, question_fi, gap_id, answertext, points, aorder, cloze_type, lowerlimit, upperlimit) VALUES (NULL, %s, %s, %s, %s, %s, %s, %s, %s)",
00395 $ilDB->quote($this->getId()),
00396 $ilDB->quote($key . ""),
00397 $ilDB->quote($item->getAnswertext() . ""),
00398 $ilDB->quote($item->getPoints() . ""),
00399 $ilDB->quote($item->getOrder() . ""),
00400 $ilDB->quote($gap->getType() . ""),
00401 $eval->e($item->getLowerBound() !== FALSE) ? $ilDB->quote($item->getLowerBound()) : "NULL",
00402 $eval->e($item->getUpperBound() !== FALSE) ? $ilDB->quote($item->getUpperBound()) : "NULL"
00403 );
00404 break;
00405 }
00406 if (strlen($query)) $answer_result = $ilDB->query($query);
00407 }
00408 }
00409 }
00410 parent::saveToDb($original_id);
00411 }
00412
00421 function getGaps()
00422 {
00423 return $this->gaps;
00424 }
00425
00426
00435 function flushGaps()
00436 {
00437 $this->gaps = array();
00438 }
00439
00451 function setClozeText($cloze_text = "")
00452 {
00453 $this->gaps = array();
00454 $cloze_text = $this->cleanQuestiontext($cloze_text);
00455 $this->question = $cloze_text;
00456 $this->createGapsFromQuestiontext();
00457 }
00458
00468 function getClozeText()
00469 {
00470 return $this->question;
00471 }
00472
00482 function getStartTag()
00483 {
00484 return $this->start_tag;
00485 }
00486
00496 function setStartTag($start_tag = "[gap]")
00497 {
00498 $this->start_tag = $start_tag;
00499 }
00500
00510 function getEndTag()
00511 {
00512 return $this->end_tag;
00513 }
00514
00524 function setEndTag($end_tag = "[/gap]")
00525 {
00526 $this->end_tag = $end_tag;
00527 }
00528
00529 function createGapsFromQuestiontext()
00530 {
00531 include_once "./Modules/TestQuestionPool/classes/class.assClozeGap.php";
00532 include_once "./Modules/TestQuestionPool/classes/class.assAnswerCloze.php";
00533 $search_pattern = "|\[gap\](.*?)\[/gap\]|i";
00534 preg_match_all($search_pattern, $this->getClozeText(), $found);
00535 $this->gaps = array();
00536 if (count($found[0]))
00537 {
00538 foreach ($found[1] as $gap_index => $answers)
00539 {
00540
00541 $gap = new assClozeGap(CLOZE_TEXT);
00542 $textparams = preg_split("/(?<!\\\\),/", $answers);
00543 foreach ($textparams as $key => $value)
00544 {
00545 $answer = new assAnswerCloze($value, 0, $key);
00546 $gap->addItem($answer);
00547 }
00548 $this->gaps[$gap_index] = $gap;
00549 }
00550 }
00551 }
00552
00560 function setGapType($gap_index, $gap_type)
00561 {
00562 if (array_key_exists($gap_index, $this->gaps))
00563 {
00564 $this->gaps[$gap_index]->setType($gap_type);
00565 }
00566 }
00567
00579 function setGapShuffle($gap_index = 0, $shuffle = 1)
00580 {
00581 if (array_key_exists($gap_index, $this->gaps))
00582 {
00583 $this->gaps[$gap_index]->setShuffle($shuffle);
00584 }
00585 }
00586
00595 function clearGapAnswers()
00596 {
00597 foreach ($this->gaps as $gap_index => $gap)
00598 {
00599 $this->gaps[$gap_index]->clearItems();
00600 }
00601 }
00602
00612 function getGapCount()
00613 {
00614 if (is_array($this->gaps))
00615 {
00616 return count($this->gaps);
00617 }
00618 else
00619 {
00620 return 0;
00621 }
00622 }
00623
00636 function addGapAnswer($gap_index, $order, $answer)
00637 {
00638 if (array_key_exists($gap_index, $this->gaps))
00639 {
00640 if ($this->gaps[$gap_index]->getType() == CLOZE_NUMERIC)
00641 {
00642
00643 $answer = str_replace(",", ".", $answer);
00644 }
00645 $this->gaps[$gap_index]->addItem(new assAnswerCloze($answer, 0, $order));
00646 }
00647 }
00648
00659 function getGap($gap_index = 0)
00660 {
00661 if (array_key_exists($gap_index, $this->gaps))
00662 {
00663 return $this->gaps[$gap_index];
00664 }
00665 else
00666 {
00667 return NULL;
00668 }
00669 }
00670
00683 function setGapAnswerPoints($gap_index, $order, $points)
00684 {
00685 if (array_key_exists($gap_index, $this->gaps))
00686 {
00687 $this->gaps[$gap_index]->setItemPoints($order, $points);
00688 }
00689 }
00690
00701 function addGapText($gap_index)
00702 {
00703 if (array_key_exists($gap_index, $this->gaps))
00704 {
00705 include_once "./Modules/TestQuestionPool/classes/class.assAnswerCloze.php";
00706 $answer = new assAnswerCloze(
00707 "",
00708 0,
00709 $this->gaps[$gap_index]->getItemCount()
00710 );
00711 $this->gaps[$gap_index]->addItem($answer);
00712 }
00713 }
00714
00725 function addGapAtIndex($gap, $index)
00726 {
00727 $this->gaps[$index] = $gap;
00728 }
00729
00742 function setGapAnswerLowerBound($gap_index, $order, $bound)
00743 {
00744 if (array_key_exists($gap_index, $this->gaps))
00745 {
00746 $this->gaps[$gap_index]->setItemLowerBound($order, $bound);
00747 }
00748 }
00749
00762 function setGapAnswerUpperBound($gap_index, $order, $bound)
00763 {
00764 if (array_key_exists($gap_index, $this->gaps))
00765 {
00766 $this->gaps[$gap_index]->setItemUpperBound($order, $bound);
00767 }
00768 }
00769
00778 function getMaximumPoints()
00779 {
00780 $points = 0;
00781 foreach ($this->gaps as $gap_index => $gap)
00782 {
00783 if ($gap->getType() == CLOZE_TEXT)
00784 {
00785 $gap_max_points = 0;
00786 foreach ($gap->getItems() as $item)
00787 {
00788 if ($item->getPoints() > $gap_max_points)
00789 {
00790 $gap_max_points = $item->getPoints();
00791 }
00792 }
00793 $points += $gap_max_points;
00794 }
00795 else if ($gap->getType() == CLOZE_SELECT)
00796 {
00797 $srpoints = 0;
00798 foreach ($gap->getItems() as $item)
00799 {
00800 if ($item->getPoints() > $srpoints)
00801 {
00802 $srpoints = $item->getPoints();
00803 }
00804 }
00805 $points += $srpoints;
00806 }
00807 else if ($gap->getType() == CLOZE_NUMERIC)
00808 {
00809 $numpoints = 0;
00810 foreach ($gap->getItems() as $item)
00811 {
00812 if ($item->getPoints() > $numpoints)
00813 {
00814 $numpoints = $item->getPoints();
00815 }
00816 }
00817 $points += $numpoints;
00818 }
00819 }
00820 return $points;
00821 }
00822
00830 function duplicate($for_test = true, $title = "", $author = "", $owner = "")
00831 {
00832 if ($this->id <= 0)
00833 {
00834
00835 return;
00836 }
00837
00838 $this_id = $this->getId();
00839 $clone = $this;
00840 include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
00841 $original_id = assQuestion::_getOriginalId($this->id);
00842 $clone->id = -1;
00843 if ($title)
00844 {
00845 $clone->setTitle($title);
00846 }
00847 if ($author)
00848 {
00849 $clone->setAuthor($author);
00850 }
00851 if ($owner)
00852 {
00853 $clone->setOwner($owner);
00854 }
00855 if ($for_test)
00856 {
00857 $clone->saveToDb($original_id);
00858 }
00859 else
00860 {
00861 $clone->saveToDb();
00862 }
00863
00864
00865 $clone->copyPageOfQuestion($this_id);
00866
00867 $clone->copyXHTMLMediaObjectsOfQuestion($this_id);
00868
00869 $clone->duplicateFeedbackGeneric($this_id);
00870
00871 return $clone->id;
00872 }
00873
00881 function copyObject($target_questionpool, $title = "")
00882 {
00883 if ($this->getId() <= 0)
00884 {
00885
00886 return;
00887 }
00888 $clone = $this;
00889 include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
00890 $original_id = assQuestion::_getOriginalId($this->getId());
00891 $clone->id = -1;
00892 $source_questionpool = $this->getObjId();
00893 $clone->setObjId($target_questionpool);
00894 if ($title)
00895 {
00896 $clone->setTitle($title);
00897 }
00898 $clone->saveToDb();
00899
00900
00901 $clone->copyPageOfQuestion($original_id);
00902
00903 $clone->copyXHTMLMediaObjectsOfQuestion($original_id);
00904
00905 $clone->duplicateFeedbackGeneric($original_id);
00906
00907 return $clone->getId();
00908 }
00909
00917 function updateClozeTextFromGaps()
00918 {
00919 $output = $this->getClozeText();
00920 foreach ($this->getGaps() as $gap_index => $gap)
00921 {
00922 $answers = array();
00923 foreach ($gap->getItemsRaw() as $item)
00924 {
00925 array_push($answers, str_replace(",", "\\,", $item->getAnswerText()));
00926 }
00927 $output = preg_replace("/\[gap\].*?\[\/gap\]/", "[_gap]" . ilUtil::prepareFormOutput(join(",", $answers)) . "[/_gap]", $output, 1);
00928 }
00929 $output = str_replace("_gap]", "gap]", $output);
00930 $this->question = $output;
00931 }
00932
00944 function deleteAnswerText($gap_index, $answer_index)
00945 {
00946 if (array_key_exists($gap_index, $this->gaps))
00947 {
00948 if ($this->gaps[$gap_index]->getItemCount() == 1)
00949 {
00950
00951 $this->deleteGap($gap_index);
00952 }
00953 else
00954 {
00955
00956 $this->gaps[$gap_index]->deleteItem($answer_index);
00957 $this->updateClozeTextFromGaps();
00958 }
00959 }
00960 }
00961
00972 function deleteGap($gap_index)
00973 {
00974 if (array_key_exists($gap_index, $this->gaps))
00975 {
00976 $output = $this->getClozeText();
00977 foreach ($this->getGaps() as $replace_gap_index => $gap)
00978 {
00979 $answers = array();
00980 foreach ($gap->getItemsRaw() as $item)
00981 {
00982 array_push($answers, str_replace(",", "\\,", $item->getAnswerText()));
00983 }
00984 if ($replace_gap_index == $gap_index)
00985 {
00986 $output = preg_replace("/\[gap\].*?\[\/gap\]/", "", $output, 1);
00987 }
00988 else
00989 {
00990 $output = preg_replace("/\[gap\].*?\[\/gap\]/", "[_gap]" . join(",", $answers) . "[/_gap]", $output, 1);
00991 }
00992 }
00993 $output = str_replace("_gap]", "gap]", $output);
00994 $this->question = $output;
00995 unset($this->gaps[$gap_index]);
00996 $this->gaps = array_values($this->gaps);
00997 }
00998 }
00999
01011 function getTextgapPoints($a_original, $a_entered, $max_points)
01012 {
01013 include_once "./Services/Utilities/classes/class.ilStr.php";
01014 $result = 0;
01015 $gaprating = $this->getTextgapRating();
01016 switch ($gaprating)
01017 {
01018 case TEXTGAP_RATING_CASEINSENSITIVE:
01019 if (strcmp(ilStr::strToLower($a_original), ilStr::strToLower($a_entered)) == 0) $result = $max_points;
01020 break;
01021 case TEXTGAP_RATING_CASESENSITIVE:
01022 if (strcmp($a_original, $a_entered) == 0) $result = $max_points;
01023 break;
01024 case TEXTGAP_RATING_LEVENSHTEIN1:
01025 if (levenshtein($a_original, $a_entered) <= 1) $result = $max_points;
01026 break;
01027 case TEXTGAP_RATING_LEVENSHTEIN2:
01028 if (levenshtein($a_original, $a_entered) <= 2) $result = $max_points;
01029 break;
01030 case TEXTGAP_RATING_LEVENSHTEIN3:
01031 if (levenshtein($a_original, $a_entered) <= 3) $result = $max_points;
01032 break;
01033 case TEXTGAP_RATING_LEVENSHTEIN4:
01034 if (levenshtein($a_original, $a_entered) <= 4) $result = $max_points;
01035 break;
01036 case TEXTGAP_RATING_LEVENSHTEIN5:
01037 if (levenshtein($a_original, $a_entered) <= 5) $result = $max_points;
01038 break;
01039 }
01040 return $result;
01041 }
01042
01054 function getNumericgapPoints($a_original, $a_entered, $max_points, $lowerBound, $upperBound)
01055 {
01056 include_once "./Services/Math/classes/class.EvalMath.php";
01057 $eval = new EvalMath();
01058 $eval->suppress_errors = TRUE;
01059 $result = 0;
01060 if (($eval->e($lowerBound) !== FALSE) && ($eval->e($upperBound) !== FALSE))
01061 {
01062 if (($eval->e($a_entered) >= $eval->e($lowerBound)) && ($eval->e($a_entered) <= $eval->e($upperBound))) $result = $max_points;
01063 }
01064 else if ($eval->e($lowerBound) !== FALSE)
01065 {
01066 if (($eval->e($a_entered) >= $eval->e($lowerBound)) && ($eval->e($a_entered) <= $eval->e($a_original))) $result = $max_points;
01067 }
01068 else if ($eval->e($upperBound) !== FALSE)
01069 {
01070 if (($eval->e($a_entered) >= $eval->e($a_original)) && ($eval->e($a_entered) <= $eval->e($upperBound))) $result = $max_points;
01071 }
01072 else
01073 {
01074 if ($eval->e($a_entered) == $eval->e($a_original)) $result = $max_points;
01075 }
01076 return $result;
01077 }
01078
01090 function calculateReachedPoints($active_id, $pass = NULL, $returndetails = FALSE)
01091 {
01092 global $ilDB;
01093
01094 $found_value1 = array();
01095 $found_value2 = array();
01096 $detailed = array();
01097 if (is_null($pass))
01098 {
01099 $pass = $this->getSolutionMaxPass($active_id);
01100 }
01101 $query = sprintf("SELECT * FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
01102 $ilDB->quote($active_id . ""),
01103 $ilDB->quote($this->getId() . ""),
01104 $ilDB->quote($pass . "")
01105 );
01106 $result = $ilDB->query($query);
01107 $user_result = array();
01108 while ($data = $result->fetchRow(DB_FETCHMODE_OBJECT))
01109 {
01110 if (strcmp($data->value2, "") != 0)
01111 {
01112 $user_result[$data->value1] = array(
01113 "gap_id" => $data->value1,
01114 "value" => $data->value2
01115 );
01116 }
01117 }
01118 $points = 0;
01119 $counter = 0;
01120 $solution_values_text = array();
01121 $solution_values_select = array();
01122 $solution_values_numeric = array();
01123 foreach ($user_result as $gap_id => $value)
01124 {
01125 if (array_key_exists($gap_id, $this->gaps))
01126 {
01127 switch ($this->gaps[$gap_id]->getType())
01128 {
01129 case CLOZE_TEXT:
01130 $gappoints = 0;
01131 for ($order = 0; $order < $this->gaps[$gap_id]->getItemCount(); $order++)
01132 {
01133 $answer = $this->gaps[$gap_id]->getItem($order);
01134 $gotpoints = $this->getTextgapPoints($answer->getAnswertext(), $value["value"], $answer->getPoints());
01135 if ($gotpoints > $gappoints) $gappoints = $gotpoints;
01136 }
01137 if (!$this->getIdenticalScoring())
01138 {
01139
01140 if ((in_array($value["value"], $solution_values_text)) && ($gappoints > 0))
01141 {
01142 $gappoints = 0;
01143 }
01144 }
01145 $points += $gappoints;
01146 $detailed[$gap_id] = array("points" =>$gappoints, "best" => ($this->getMaximumGapPoints($gap_id) == $gappoints) ? TRUE : FALSE, "positive" => ($gappoints > 0) ? TRUE : FALSE);
01147 array_push($solution_values_text, $value["value"]);
01148 break;
01149 case CLOZE_NUMERIC:
01150 $gappoints = 0;
01151 for ($order = 0; $order < $this->gaps[$gap_id]->getItemCount(); $order++)
01152 {
01153 $answer = $this->gaps[$gap_id]->getItem($order);
01154 $gotpoints = $this->getNumericgapPoints($answer->getAnswertext(), $value["value"], $answer->getPoints(), $answer->getLowerBound(), $answer->getUpperBound());
01155 if ($gotpoints > $gappoints) $gappoints = $gotpoints;
01156 }
01157 if (!$this->getIdenticalScoring())
01158 {
01159
01160 include_once "./Services/Math/classes/class.EvalMath.php";
01161 $eval = new EvalMath();
01162 $eval->suppress_errors = TRUE;
01163 $found_value = FALSE;
01164 foreach ($solution_values_numeric as $solval)
01165 {
01166 if ($eval->e($solval) == $eval->e($value["value"]))
01167 {
01168 $found_value = TRUE;
01169 }
01170 }
01171 if ($found_value && ($gappoints > 0))
01172 {
01173 $gappoints = 0;
01174 }
01175 }
01176 $points += $gappoints;
01177 $detailed[$gap_id] = array("points" =>$gappoints, "best" => ($this->getMaximumGapPoints($gap_id) == $gappoints) ? TRUE : FALSE, "positive" => ($gappoints > 0) ? TRUE : FALSE);
01178 array_push($solution_values_numeric, $value["value"]);
01179 break;
01180 case CLOZE_SELECT:
01181 if ($value["value"] >= 0)
01182 {
01183 for ($order = 0; $order < $this->gaps[$gap_id]->getItemCount(); $order++)
01184 {
01185 $answer = $this->gaps[$gap_id]->getItem($order);
01186 if ($value["value"] == $answer->getOrder())
01187 {
01188 $answerpoints = $answer->getPoints();
01189 if (!$this->getIdenticalScoring())
01190 {
01191
01192 if ((in_array($answer->getAnswertext(), $solution_values_select)) && ($answerpoints > 0))
01193 {
01194 $answerpoints = 0;
01195 }
01196 }
01197 $points += $answerpoints;
01198 $detailed[$gap_id] = array("points" =>$answerpoints, "best" => ($this->getMaximumGapPoints($gap_id) == $answerpoints) ? TRUE : FALSE, "positive" => ($answerpoints > 0) ? TRUE : FALSE);
01199 array_push($solution_values_select, $answer->getAnswertext());
01200 }
01201 }
01202 }
01203 break;
01204 }
01205 }
01206 }
01207 if ($returndetails)
01208 {
01209 return $detailed;
01210 }
01211 else
01212 {
01213 $points = parent::calculateReachedPoints($active_id, $pass = NULL, $points);
01214 return $points;
01215 }
01216 }
01217
01228 function saveWorkingData($active_id, $pass = NULL)
01229 {
01230 global $ilDB;
01231 global $ilUser;
01232 if (is_null($pass))
01233 {
01234 include_once "./Modules/Test/classes/class.ilObjTest.php";
01235 $pass = ilObjTest::_getPass($active_id);
01236 }
01237
01238 $query = sprintf("DELETE FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
01239 $ilDB->quote($active_id),
01240 $ilDB->quote($this->getId()),
01241 $ilDB->quote($pass . "")
01242 );
01243 $result = $ilDB->query($query);
01244
01245 $entered_values = 0;
01246 foreach ($_POST as $key => $value)
01247 {
01248 if (preg_match("/^gap_(\d+)/", $key, $matches))
01249 {
01250 $value = ilUtil::stripSlashes($value, FALSE);
01251 if (strlen($value))
01252 {
01253 $gap = $this->getGap($matches[1]);
01254 if (is_object($gap))
01255 {
01256 if (!(($gap->getType() == CLOZE_SELECT) && ($value == -1)))
01257 {
01258 if ($gap->getType() == CLOZE_NUMERIC)
01259 {
01260 $value = str_replace(",", ".", $value);
01261 }
01262 $query = sprintf("INSERT INTO tst_solutions (solution_id, active_fi, question_fi, value1, value2, pass, TIMESTAMP) VALUES (NULL, %s, %s, %s, %s, %s, NULL)",
01263 $ilDB->quote($active_id),
01264 $ilDB->quote($this->getId()),
01265 $ilDB->quote(trim($matches[1])),
01266 $ilDB->quote(trim($value)),
01267 $ilDB->quote($pass . "")
01268 );
01269 $result = $ilDB->query($query);
01270 $entered_values++;
01271 }
01272 }
01273 }
01274 }
01275 }
01276 if ($entered_values)
01277 {
01278 include_once ("./classes/class.ilObjAssessmentFolder.php");
01279 if (ilObjAssessmentFolder::_enabledAssessmentLogging())
01280 {
01281 $this->logAction($this->lng->txtlng("assessment", "log_user_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
01282 }
01283 }
01284 else
01285 {
01286 include_once ("./classes/class.ilObjAssessmentFolder.php");
01287 if (ilObjAssessmentFolder::_enabledAssessmentLogging())
01288 {
01289 $this->logAction($this->lng->txtlng("assessment", "log_user_not_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
01290 }
01291 }
01292 parent::saveWorkingData($active_id, $pass);
01293 return true;
01294 }
01295
01304 function getQuestionType()
01305 {
01306 return "assClozeTest";
01307 }
01308
01318 function getTextgapRating()
01319 {
01320 return $this->textgap_rating;
01321 }
01322
01332 function setTextgapRating($a_textgap_rating)
01333 {
01334 switch ($a_textgap_rating)
01335 {
01336 case TEXTGAP_RATING_CASEINSENSITIVE:
01337 case TEXTGAP_RATING_CASESENSITIVE:
01338 case TEXTGAP_RATING_LEVENSHTEIN1:
01339 case TEXTGAP_RATING_LEVENSHTEIN2:
01340 case TEXTGAP_RATING_LEVENSHTEIN3:
01341 case TEXTGAP_RATING_LEVENSHTEIN4:
01342 case TEXTGAP_RATING_LEVENSHTEIN5:
01343 $this->textgap_rating = $a_textgap_rating;
01344 break;
01345 default:
01346 $this->textgap_rating = TEXTGAP_RATING_CASEINSENSITIVE;
01347 break;
01348 }
01349 }
01350
01360 function getIdenticalScoring()
01361 {
01362 return ($this->identical_scoring) ? 1 : 0;
01363 }
01364
01374 function setIdenticalScoring($a_identical_scoring)
01375 {
01376 $this->identical_scoring = ($a_identical_scoring) ? 1 : 0;
01377 }
01378
01387 function getAdditionalTableName()
01388 {
01389 return "qpl_question_cloze";
01390 }
01391
01400 function getAnswerTableName()
01401 {
01402 return "qpl_answer_cloze";
01403 }
01404
01413 function setFixedTextLength($a_text_len)
01414 {
01415 $this->fixedTextLength = $a_text_len;
01416 }
01417
01426 function getFixedTextLength()
01427 {
01428 return $this->fixedTextLength;
01429 }
01430
01441 function getMaximumGapPoints($gap_index)
01442 {
01443 $points = 0;
01444 if (array_key_exists($gap_index, $this->gaps))
01445 {
01446 $gap =& $this->gaps[$gap_index];
01447 foreach ($gap->getItems() as $answer)
01448 {
01449 if ($answer->getPoints() > $gap_max_points)
01450 {
01451 $gap_max_points = $answer->getPoints();
01452 }
01453 }
01454 $points += $gap_max_points;
01455 }
01456 return $points;
01457 }
01458
01463 function getRTETextWithMediaObjects()
01464 {
01465 return parent::getRTETextWithMediaObjects();
01466 }
01467
01468
01469 }
01470 ?>