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 require_once "./assessment/classes/class.assQuestion.php";
00025 require_once "./assessment/classes/class.assAnswerCloze.php";
00026 require_once "./assessment/classes/class.ilQTIUtils.php";
00027
00028 define("CLOZE_TEXT", "0");
00029 define("CLOZE_SELECT", "1");
00030 define("CLOZE_TEST_IDENTIFIER", "CLOZE QUESTION");
00031
00042 class ASS_ClozeTest extends ASS_Question
00043 {
00052 var $cloze_text;
00053
00061 var $gaps;
00062
00070 var $start_tag;
00071
00079 var $end_tag;
00092 function ASS_ClozeTest(
00093 $title = "",
00094 $comment = "",
00095 $author = "",
00096 $owner = -1,
00097 $cloze_text = ""
00098 )
00099 {
00100 $this->start_tag = "<gap>";
00101 $this->end_tag = "</gap>";
00102 $this->ASS_Question($title, $comment, $author, $owner);
00103 $this->gaps = array();
00104 $this->set_cloze_text($cloze_text);
00105 }
00106
00115 function isComplete()
00116 {
00117 if (($this->title) and ($this->author) and ($this->cloze_text) and (count($this->gaps)))
00118 {
00119 return true;
00120 }
00121 else
00122 {
00123 return false;
00124 }
00125 }
00126
00135 function &createCloseTextArray()
00136 {
00137 $result = array();
00138 $search_pattern = "|<gap([^>]*?)>(.*?)</gap>|i";
00139 preg_match_all($search_pattern, $this->cloze_text, $gaps);
00140 if (count($gaps[0]))
00141 {
00142
00143 $delimiters = preg_split($search_pattern, $this->cloze_text, -1, PREG_SPLIT_OFFSET_CAPTURE);
00144 $result["gaps"] = array();
00145 foreach ($gaps[0] as $index => $gap)
00146 {
00147 $result["gaps"][$index] = array();
00148 $result["gaps"][$index]["gap"] = $gap;
00149 $result["gaps"][$index]["params"] = array();
00150 $result["gaps"][$index]["params"]["text"] = $gaps[1][$index];
00151
00152 if (preg_match("/name\=\"([^\"]*?)\"/", $gaps[1][$index], $params))
00153 {
00154 $result["gaps"][$index]["params"]["name"] = $params[1];
00155 }
00156 else
00157 {
00158 $result["gaps"][$index]["params"]["name"] = $this->lng->txt("gap") . " " . ($index+1);
00159 }
00160 if (preg_match("/type\=\"([^\"]*?)\"/", $gaps[1][$index], $params))
00161 {
00162 $result["gaps"][$index]["params"]["type"] = $params[1];
00163 }
00164 else
00165 {
00166 $result["gaps"][$index]["params"]["type"] = "text";
00167 }
00168 if (preg_match("/shuffle\=\"([^\"]*?)\"/", $gaps[1][$index], $params))
00169 {
00170 $result["gaps"][$index]["params"]["shuffle"] = $params[1];
00171 }
00172 else
00173 {
00174 if (strcmp(strtolower($result["gaps"][$index]["params"]["type"]), "select") == 0)
00175 {
00176 $result["gaps"][$index]["params"]["shuffle"] = "yes";
00177 }
00178 }
00179 $result["gaps"][$index]["text"] = array();
00180 $result["gaps"][$index]["text"]["text"] = $gaps[2][$index];
00181 $textparams = preg_split("/(?<!\\\\),/", $gaps[2][$index]);
00182 foreach ($textparams as $key => $value)
00183 {
00184 $result["gaps"][$index]["text"][$key] = $value;
00185 }
00186 }
00187 $result["delimiters"] = $delimiters;
00188 }
00189 else
00190 {
00191 $result["gaps"] = array();
00192 $result["delimiters"] =
00193 array(
00194 array(0 => $this->cloze_text, 1 => "0")
00195 );
00196 }
00197
00198 return $result;
00199 }
00200
00209 function createCloseTextFromArray($assoc_array)
00210 {
00211 $this->cloze_text = "";
00212 if (count($assoc_array))
00213 {
00214 $gap = 0;
00215 foreach ($assoc_array["delimiters"] as $key => $value)
00216 {
00217 if (($key > 0) && ($key < count($assoc_array["delimiters"])))
00218 {
00219 if (strcmp($assoc_array["gaps"][$gap]["params"]["shuffle"], "") == 0)
00220 {
00221 $shuffle = "";
00222 }
00223 else
00224 {
00225 $shuffle = " shuffle=\"" . $assoc_array["gaps"][$gap]["params"]["shuffle"] . "\"";
00226 }
00227 $textarray = array();
00228 foreach ($assoc_array["gaps"][$gap]["text"] as $textindex => $textvalue)
00229 {
00230 if (preg_match("/\d+/", $textindex))
00231 {
00232 array_push($textarray, $textvalue);
00233 }
00234 }
00235 $this->cloze_text .= sprintf("<gap name=\"%s\" type=\"%s\"%s>%s</gap>",
00236 $assoc_array["gaps"][$gap]["params"]["name"],
00237 $assoc_array["gaps"][$gap]["params"]["type"],
00238 $shuffle,
00239 join(",", $textarray)
00240 );
00241 $gap++;
00242 }
00243 $this->cloze_text .= $value[0];
00244 }
00245 }
00246 }
00247
00256 function saveToDb($original_id = "")
00257 {
00258 global $ilias;
00259
00260 $db =& $ilias->db;
00261 $complete = 0;
00262 if ($this->isComplete())
00263 {
00264 $complete = 1;
00265 }
00266
00267 $estw_time = $this->getEstimatedWorkingTime();
00268 $estw_time = sprintf("%02d:%02d:%02d", $estw_time['h'], $estw_time['m'], $estw_time['s']);
00269 $shuffle = 1;
00270
00271 if (!$this->shuffle)
00272 {
00273 $shuffle = 0;
00274 }
00275
00276 if ($original_id)
00277 {
00278 $original_id = $db->quote($original_id);
00279 }
00280 else
00281 {
00282 $original_id = "NULL";
00283 }
00284
00285 if ($this->id == -1)
00286 {
00287
00288 $now = getdate();
00289 $created = sprintf("%04d%02d%02d%02d%02d%02d", $now['year'], $now['mon'], $now['mday'], $now['hours'], $now['minutes'], $now['seconds']);
00290 $query = sprintf("INSERT INTO qpl_questions (question_id, question_type_fi, obj_fi, title, comment, points, author, owner, question_text, working_time, shuffle, complete, created, original_id, TIMESTAMP) VALUES (NULL, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, NULL)",
00291 $db->quote($this->getQuestionType()),
00292 $db->quote($this->obj_id),
00293 $db->quote($this->title),
00294 $db->quote($this->comment),
00295 $db->quote($this->getMaximumPoints() . ""),
00296 $db->quote($this->author),
00297 $db->quote($this->owner),
00298 $db->quote($this->cloze_text),
00299 $db->quote($estw_time),
00300 $db->quote("$this->shuffle"),
00301 $db->quote("$complete"),
00302 $db->quote($created),
00303 $original_id
00304 );
00305 $result = $db->query($query);
00306 if ($result == DB_OK)
00307 {
00308 $this->id = $this->ilias->db->getLastInsertId();
00309
00310
00311 $this->createPageObject();
00312
00313
00314 if ($this->getTestId() > 0)
00315 {
00316 $this->insertIntoTest($this->getTestId());
00317 }
00318 }
00319 }
00320 else
00321 {
00322
00323 $query = sprintf("UPDATE qpl_questions SET obj_fi = %s, title = %s, comment = %s, points = %s, author = %s, question_text = %s, working_time = %s, shuffle = %s, complete = %s WHERE question_id = %s",
00324 $db->quote($this->obj_id. ""),
00325 $db->quote($this->title),
00326 $db->quote($this->comment),
00327 $db->quote($this->getMaximumPoints() . ""),
00328 $db->quote($this->author),
00329 $db->quote($this->cloze_text),
00330 $db->quote($estw_time),
00331 $db->quote("$this->shuffle"),
00332 $db->quote("$complete"),
00333 $db->quote($this->id)
00334 );
00335 $result = $db->query($query);
00336 }
00337
00338 if ($result == DB_OK)
00339 {
00340
00341
00342
00343 $query = sprintf("DELETE FROM qpl_answers WHERE question_fi = %s",
00344 $db->quote($this->id)
00345 );
00346 $result = $db->query($query);
00347
00348 foreach ($this->gaps as $key => $value)
00349 {
00350 foreach ($value as $answer_id => $answer_obj)
00351 {
00352 $query = sprintf("INSERT INTO qpl_answers (answer_id, question_fi, gap_id, answertext, points, aorder, cloze_type, name, shuffle, correctness, TIMESTAMP) VALUES (NULL, %s, %s, %s, %s, %s, %s, %s, %s, %s, NULL)",
00353 $db->quote($this->id),
00354 $db->quote($key),
00355 $db->quote($answer_obj->get_answertext() . ""),
00356 $db->quote($answer_obj->get_points() . ""),
00357 $db->quote($answer_obj->get_order() . ""),
00358 $db->quote($answer_obj->get_cloze_type() . ""),
00359 $db->quote($answer_obj->get_name() . ""),
00360 $db->quote($answer_obj->get_shuffle() . ""),
00361 $db->quote($answer_obj->getState() . "")
00362 );
00363 $answer_result = $db->query($query);
00364 }
00365 }
00366 }
00367 parent::saveToDb($original_id);
00368 }
00369
00379 function loadFromDb($question_id)
00380 {
00381 global $ilias;
00382 $db =& $ilias->db;
00383
00384 $query = sprintf("SELECT * FROM qpl_questions WHERE question_id = %s",
00385 $db->quote($question_id)
00386 );
00387 $result = $db->query($query);
00388 if (strcmp(strtolower(get_class($result)), db_result) == 0) {
00389 if ($result->numRows() == 1) {
00390 $data = $result->fetchRow(DB_FETCHMODE_OBJECT);
00391 $this->id = $question_id;
00392 $this->obj_id = $data->obj_fi;
00393 $this->title = $data->title;
00394 $this->comment = $data->comment;
00395 $this->solution_hint = $data->solution_hint;
00396 $this->original_id = $data->original_id;
00397 $this->author = $data->author;
00398 $this->points = $data->points;
00399 $this->owner = $data->owner;
00400 $this->cloze_text = $data->question_text;
00401 $this->shuffle = $data->shuffle;
00402 $this->setEstimatedWorkingTime(substr($data->working_time, 0, 2), substr($data->working_time, 3, 2), substr($data->working_time, 6, 2));
00403 }
00404
00405 $query = sprintf("SELECT * FROM qpl_answers WHERE question_fi = %s ORDER BY gap_id, aorder ASC",
00406 $db->quote($question_id)
00407 );
00408 $result = $db->query($query);
00409 if (strcmp(strtolower(get_class($result)), db_result) == 0) {
00410 $counter = -1;
00411 while ($data = $result->fetchRow(DB_FETCHMODE_OBJECT)) {
00412 if ($data->gap_id != $counter) {
00413 $answer_array = array();
00414 array_push($this->gaps, $answer_array);
00415 $counter = $data->gap_id;
00416 }
00417 if ($data->cloze_type == CLOZE_SELECT)
00418 {
00419 if ($data->correctness == 0)
00420 {
00421
00422 $data->correctness = 1;
00423 $data->points = 0;
00424 }
00425 }
00426 array_push($this->gaps[$counter], new ASS_AnswerCloze($data->answertext, $data->points, $data->aorder, $data->correctness, $data->cloze_type, $data->name, $data->shuffle, $data->answer_id));
00427 }
00428 }
00429 }
00430 parent::loadFromDb($question_id);
00431 }
00432
00440 function addAnswer($gap, $answertext, $points, $answerorder, $correctness, $clozetype, $name, $shuffle, $answer_id = -1)
00441 {
00442 if (!is_array($this->gaps[$gap]))
00443 {
00444 $this->gaps[$gap] = array();
00445 }
00446 array_push($this->gaps[$gap], new ASS_AnswerCloze($answertext, $points, $answerorder, $correctness, $clozetype, $name, $shuffle, $answer_id));
00447 }
00448
00456 function duplicate($for_test = true, $title = "", $author = "", $owner = "")
00457 {
00458 if ($this->id <= 0)
00459 {
00460
00461 return;
00462 }
00463
00464 $clone = $this;
00465 include_once ("./assessment/classes/class.assQuestion.php");
00466 $original_id = ASS_Question::_getOriginalId($this->id);
00467 $clone->id = -1;
00468 if ($title)
00469 {
00470 $clone->setTitle($title);
00471 }
00472 if ($author)
00473 {
00474 $clone->setAuthor($author);
00475 }
00476 if ($owner)
00477 {
00478 $clone->setOwner($owner);
00479 }
00480 if ($for_test)
00481 {
00482 $clone->saveToDb($original_id);
00483 }
00484 else
00485 {
00486 $clone->saveToDb();
00487 }
00488
00489
00490 $clone->copyPageOfQuestion($original_id);
00491
00492 return $clone->id;
00493 }
00494
00504 function from_xml($xml_text)
00505 {
00506 $result = false;
00507 if (!empty($this->domxml))
00508 {
00509 $this->domxml->free();
00510 }
00511 $xml_text = preg_replace("/>\s*?</", "><", $xml_text);
00512 $this->domxml = domxml_open_mem($xml_text);
00513 if (!empty($this->domxml))
00514 {
00515 $root = $this->domxml->document_element();
00516 $item = $root->first_child();
00517 $this->setTitle($item->get_attribute("title"));
00518 $this->gaps = array();
00519 $itemnodes = $item->child_nodes();
00520 $materials = array();
00521 $gapcounter = 0;
00522 foreach ($itemnodes as $index => $node)
00523 {
00524 switch ($node->node_name())
00525 {
00526 case "qticomment":
00527 $comment = $node->get_content();
00528 if (strpos($comment, "ILIAS Version=") !== false)
00529 {
00530 }
00531 elseif (strpos($comment, "Questiontype=") !== false)
00532 {
00533 }
00534 elseif (strpos($comment, "Author=") !== false)
00535 {
00536 $comment = str_replace("Author=", "", $comment);
00537 $this->setAuthor($comment);
00538 }
00539 else
00540 {
00541 $this->setComment($comment);
00542 }
00543 break;
00544 case "itemmetadata":
00545 $md_array = array();
00546 $metanodes = $node->child_nodes();
00547 foreach ($metanodes as $metanode)
00548 {
00549 switch ($metanode->node_name())
00550 {
00551 case "qtimetadata":
00552 $metafields = $metanode->child_nodes();
00553 foreach ($metafields as $metafield)
00554 {
00555 switch ($metafield->node_name())
00556 {
00557 case "qtimetadatafield":
00558 $metafieldlist = $metafield->child_nodes();
00559 $md = array("label" => "", "entry" => "");
00560 foreach ($metafieldlist as $attr)
00561 {
00562 switch ($attr->node_name())
00563 {
00564 case "fieldlabel":
00565 $md["label"] = $attr->get_content();
00566 break;
00567 case "fieldentry":
00568 $md["entry"] = $attr->get_content();
00569 break;
00570 }
00571 }
00572 array_push($md_array, $md);
00573 break;
00574 }
00575 }
00576 break;
00577 }
00578 }
00579 foreach ($md_array as $md)
00580 {
00581 switch ($md["label"])
00582 {
00583 case "ILIAS_VERSION":
00584 break;
00585 case "QUESTIONTYPE":
00586 break;
00587 case "AUTHOR":
00588 $this->setAuthor($md["entry"]);
00589 break;
00590 }
00591 }
00592 break;
00593 case "duration":
00594 $iso8601period = $node->get_content();
00595 if (preg_match("/P(\d+)Y(\d+)M(\d+)DT(\d+)H(\d+)M(\d+)S/", $iso8601period, $matches))
00596 {
00597 $this->setEstimatedWorkingTime($matches[4], $matches[5], $matches[6]);
00598 }
00599 break;
00600 case "presentation":
00601 $flow = $node->first_child();
00602 $flownodes = $flow->child_nodes();
00603 foreach ($flownodes as $idx => $flownode)
00604 {
00605 if (strcmp($flownode->node_name(), "material") == 0)
00606 {
00607 $mattext = $flownode->first_child();
00608 array_push($materials, $mattext->get_content());
00609 }
00610 elseif (strcmp($flownode->node_name(), "response_str") == 0)
00611 {
00612 $ident = $flownode->get_attribute("ident");
00613 $this->gaps["$ident"] = array();
00614 $shuffle = "";
00615 $subnodes = $flownode->child_nodes();
00616 foreach ($subnodes as $node_type)
00617 {
00618 switch ($node_type->node_name())
00619 {
00620 case "render_choice":
00621 $render_type = $node_type;
00622 if (strcmp($render_type->node_name(), "render_choice") == 0)
00623 {
00624
00625 $shuffle = $render_type->get_attribute("shuffle");
00626 $labels = $render_type->child_nodes();
00627 foreach ($labels as $lidx => $response_label)
00628 {
00629 $material = $response_label->first_child();
00630 $mattext = $material->first_child();
00631 $shuf = 0;
00632 if (strcmp(strtolower($shuffle), "yes") == 0)
00633 {
00634 $shuf = 1;
00635 }
00636 array_push($this->gaps["$ident"], new ASS_AnswerCloze($mattext->get_content(), 0, count($this->gaps["$ident"]), 0, CLOZE_SELECT, $ident, $shuf));
00637 }
00638 }
00639 break;
00640 case "render_fib":
00641 break;
00642 case "material":
00643 $matlabel = $node_type->get_attribute("label");
00644 if (strcmp($matlabel, "suggested_solution") == 0)
00645 {
00646 $mattype = $node_type->first_child();
00647 if (strcmp($mattype->node_name(), "mattext") == 0)
00648 {
00649 $suggested_solution = $mattype->get_content();
00650 if ($suggested_solution)
00651 {
00652 if ($this->getId() < 1)
00653 {
00654 $this->saveToDb();
00655 }
00656 if (preg_match("/gap_(\d+)/", $ident, $matches))
00657 {
00658 $this->setSuggestedSolution($suggested_solution, $matches[1], true);
00659 }
00660 }
00661 }
00662 }
00663 break;
00664 }
00665 }
00666 }
00667 }
00668 break;
00669 case "resprocessing":
00670 $resproc_nodes = $node->child_nodes();
00671 foreach ($resproc_nodes as $index => $respcondition)
00672 {
00673 if (strcmp($respcondition->node_name(), "respcondition") == 0)
00674 {
00675 $respcondition_array =& ilQTIUtils::_getRespcondition($respcondition);
00676 $found_answer = 0;
00677 foreach ($this->gaps[$respcondition_array["conditionvar"]["respident"]] as $key => $value)
00678 {
00679 if (strcmp($value->get_answertext(), $respcondition_array["conditionvar"]["value"]) == 0)
00680 {
00681 $found_answer = 1;
00682 $this->gaps[$respcondition_array["conditionvar"]["respident"]][$key]->set_points($respcondition_array["setvar"]["points"]);
00683 if ($respcondition_array["conditionvar"]["selected"])
00684 {
00685 $this->gaps[$respcondition_array["conditionvar"]["respident"]][$key]->setChecked();
00686 }
00687 }
00688 }
00689 if (!$found_answer)
00690 {
00691
00692 array_push($this->gaps[$respcondition_array["conditionvar"]["respident"]], new ASS_AnswerCloze($respcondition_array["conditionvar"]["value"], $respcondition_array["setvar"]["points"], count($this->gaps[$respcondition_array["conditionvar"]["respident"]]), 1, CLOZE_TEXT, $respcondition_array["conditionvar"]["respident"], 0));
00693 }
00694 }
00695 }
00696 break;
00697 }
00698 }
00699 $this->gaps = array_values($this->gaps);
00700 $i = 0;
00701 foreach ($materials as $key => $value)
00702 {
00703 $this->cloze_text .= $value;
00704 $gaptext = $this->get_gap_text_list($i);
00705 if ($gaptext)
00706 {
00707 $type = " type=\"select\"";
00708 if ($this->gaps[$i][0]->get_cloze_type() == CLOZE_TEXT)
00709 {
00710 $type = " type=\"text\"";
00711 }
00712 $shuffle = " shuffle=\"yes\"";
00713 if (!$this->gaps[$i][0]->get_shuffle())
00714 {
00715 $shuffle = " shuffle=\"no\"";
00716 }
00717 $this->cloze_text .= "<gap$type$shuffle>$gaptext</gap>";
00718 }
00719 $i++;
00720 }
00721 $result = true;
00722 }
00723 return $result;
00724 }
00725
00735 function to_xml($a_include_header = true, $a_include_binary = true, $a_shuffle = false, $test_output = false)
00736 {
00737 if (!empty($this->domxml))
00738 {
00739 $this->domxml->free();
00740 }
00741 $xml_header = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<questestinterop></questestinterop>\n";
00742 $this->domxml = domxml_open_mem($xml_header);
00743 $root = $this->domxml->document_element();
00744
00745 $qtiIdent = $this->domxml->create_element("item");
00746 $qtiIdent->set_attribute("ident", "il_".IL_INST_ID."_qst_".$this->getId());
00747 $qtiIdent->set_attribute("title", $this->getTitle());
00748 $root->append_child($qtiIdent);
00749
00750 $qtiComment = $this->domxml->create_element("qticomment");
00751 $qtiCommentText = $this->domxml->create_text_node($this->getComment());
00752 $qtiComment->append_child($qtiCommentText);
00753 $qtiIdent->append_child($qtiComment);
00754
00755 $qtiDuration = $this->domxml->create_element("duration");
00756 $workingtime = $this->getEstimatedWorkingTime();
00757 $qtiDurationText = $this->domxml->create_text_node(sprintf("P0Y0M0DT%dH%dM%dS", $workingtime["h"], $workingtime["m"], $workingtime["s"]));
00758 $qtiDuration->append_child($qtiDurationText);
00759 $qtiIdent->append_child($qtiDuration);
00760
00761
00762 $qtiItemmetadata = $this->domxml->create_element("itemmetadata");
00763 $qtiMetadata = $this->domxml->create_element("qtimetadata");
00764
00765 $qtiMetadatafield = $this->domxml->create_element("qtimetadatafield");
00766 $qtiFieldlabel = $this->domxml->create_element("fieldlabel");
00767 $qtiFieldlabelText = $this->domxml->create_text_node("ILIAS_VERSION");
00768 $qtiFieldlabel->append_child($qtiFieldlabelText);
00769 $qtiFieldentry = $this->domxml->create_element("fieldentry");
00770 $qtiFieldentryText = $this->domxml->create_text_node($this->ilias->getSetting("ilias_version"));
00771 $qtiFieldentry->append_child($qtiFieldentryText);
00772 $qtiMetadatafield->append_child($qtiFieldlabel);
00773 $qtiMetadatafield->append_child($qtiFieldentry);
00774 $qtiMetadata->append_child($qtiMetadatafield);
00775
00776 $qtiMetadatafield = $this->domxml->create_element("qtimetadatafield");
00777 $qtiFieldlabel = $this->domxml->create_element("fieldlabel");
00778 $qtiFieldlabelText = $this->domxml->create_text_node("QUESTIONTYPE");
00779 $qtiFieldlabel->append_child($qtiFieldlabelText);
00780 $qtiFieldentry = $this->domxml->create_element("fieldentry");
00781 $qtiFieldentryText = $this->domxml->create_text_node(CLOZE_TEST_IDENTIFIER);
00782 $qtiFieldentry->append_child($qtiFieldentryText);
00783 $qtiMetadatafield->append_child($qtiFieldlabel);
00784 $qtiMetadatafield->append_child($qtiFieldentry);
00785 $qtiMetadata->append_child($qtiMetadatafield);
00786
00787 $qtiMetadatafield = $this->domxml->create_element("qtimetadatafield");
00788 $qtiFieldlabel = $this->domxml->create_element("fieldlabel");
00789 $qtiFieldlabelText = $this->domxml->create_text_node("AUTHOR");
00790 $qtiFieldlabel->append_child($qtiFieldlabelText);
00791 $qtiFieldentry = $this->domxml->create_element("fieldentry");
00792 $qtiFieldentryText = $this->domxml->create_text_node($this->getAuthor());
00793 $qtiFieldentry->append_child($qtiFieldentryText);
00794 $qtiMetadatafield->append_child($qtiFieldlabel);
00795 $qtiMetadatafield->append_child($qtiFieldentry);
00796 $qtiMetadata->append_child($qtiMetadatafield);
00797
00798 $qtiItemmetadata->append_child($qtiMetadata);
00799 $qtiIdent->append_child($qtiItemmetadata);
00800
00801
00802 $qtiPresentation = $this->domxml->create_element("presentation");
00803 $qtiPresentation->set_attribute("label", $this->getTitle());
00804
00805 $qtiFlow = $this->domxml->create_element("flow");
00806
00807 $text_parts = preg_split("/<gap.*?<\/gap>/", $this->get_cloze_text());
00808
00809 for ($i = 0; $i <= $this->get_gap_count(); $i++)
00810 {
00811
00812 $qtiMaterial = $this->domxml->create_element("material");
00813 $qtiMatText = $this->domxml->create_element("mattext");
00814 $qtiMatTextText = $this->domxml->create_text_node($text_parts[$i]);
00815 $qtiMatText->append_child($qtiMatTextText);
00816 $qtiMaterial->append_child($qtiMatText);
00817 $qtiFlow->append_child($qtiMaterial);
00818
00819 if ($i < $this->get_gap_count())
00820 {
00821
00822 $gap = $this->get_gap($i);
00823 if ($gap[0]->get_cloze_type() == CLOZE_SELECT)
00824 {
00825
00826 $qtiResponseStr = $this->domxml->create_element("response_str");
00827 $qtiResponseStr->set_attribute("ident", "gap_$i");
00828 $qtiResponseStr->set_attribute("rcardinality", "Single");
00829 $solution = $this->getSuggestedSolution($i);
00830 if (count($solution))
00831 {
00832 if (preg_match("/il_(\d*?)_(\w+)_(\d+)/", $solution["internal_link"], $matches))
00833 {
00834 $qtiMaterial = $this->domxml->create_element("material");
00835 $qtiMaterial->set_attribute("label", "suggested_solution");
00836 $qtiMatText = $this->domxml->create_element("mattext");
00837 $intlink = "il_" . IL_INST_ID . "_" . $matches[2] . "_" . $matches[3];
00838 if (strcmp($matches[1], "") != 0)
00839 {
00840 $intlink = $solution["internal_link"];
00841 }
00842 $qtiMatTextText = $this->domxml->create_text_node($intlink);
00843 $qtiMatText->append_child($qtiMatTextText);
00844 $qtiMaterial->append_child($qtiMatText);
00845 $qtiResponseStr->append_child($qtiMaterial);
00846 }
00847 }
00848
00849 $qtiRenderChoice = $this->domxml->create_element("render_choice");
00850
00851 if ($gap[0]->get_shuffle())
00852 {
00853 $qtiRenderChoice->set_attribute("shuffle", "Yes");
00854 }
00855 else
00856 {
00857 $qtiRenderChoice->set_attribute("shuffle", "No");
00858 }
00859
00860 $gkeys = array_keys($gap);
00861 if ($gap[0]->get_shuffle() && $a_shuffle)
00862 {
00863 $gkeys = $this->pcArrayShuffle($gkeys);
00864 }
00865
00866
00867 foreach ($gkeys as $key)
00868 {
00869 $value = $gap[$key];
00870 $qtiResponseLabel = $this->domxml->create_element("response_label");
00871 $qtiResponseLabel->set_attribute("ident", $key);
00872 $qtiMaterial = $this->domxml->create_element("material");
00873 $qtiMatText = $this->domxml->create_element("mattext");
00874 $tmpvalue = $value->get_answertext();
00875 $qtiMatTextText = $this->domxml->create_text_node($tmpvalue);
00876 $qtiMatText->append_child($qtiMatTextText);
00877 $qtiMaterial->append_child($qtiMatText);
00878 $qtiResponseLabel->append_child($qtiMaterial);
00879 $qtiRenderChoice->append_child($qtiResponseLabel);
00880 }
00881 $qtiResponseStr->append_child($qtiRenderChoice);
00882 $qtiFlow->append_child($qtiResponseStr);
00883 }
00884 else
00885 {
00886
00887 $qtiResponseStr = $this->domxml->create_element("response_str");
00888 $qtiResponseStr->set_attribute("ident", "gap_$i");
00889 $qtiResponseStr->set_attribute("rcardinality", "Single");
00890 $solution = $this->getSuggestedSolution($i);
00891 if (count($solution))
00892 {
00893 if (preg_match("/il_(\d*?)_(\w+)_(\d+)/", $solution["internal_link"], $matches))
00894 {
00895 $qtiMaterial = $this->domxml->create_element("material");
00896 $qtiMaterial->set_attribute("label", "suggested_solution");
00897 $qtiMatText = $this->domxml->create_element("mattext");
00898 $intlink = "il_" . IL_INST_ID . "_" . $matches[2] . "_" . $matches[3];
00899 if (strcmp($matches[1], "") != 0)
00900 {
00901 $intlink = $solution["internal_link"];
00902 }
00903 $qtiMatTextText = $this->domxml->create_text_node($intlink);
00904 $qtiMatText->append_child($qtiMatTextText);
00905 $qtiMaterial->append_child($qtiMatText);
00906 $qtiResponseStr->append_child($qtiMaterial);
00907 }
00908 }
00909 $qtiRenderFib = $this->domxml->create_element("render_fib");
00910 $qtiRenderFib->set_attribute("fibtype", "String");
00911 $qtiRenderFib->set_attribute("prompt", "Box");
00912 $qtiRenderFib->set_attribute("columns", $this->getColumnSize($gap));
00913 $qtiResponseLabel = $this->domxml->create_element("response_label");
00914 $qtiResponseLabel->set_attribute("ident", $i);
00915 $qtiRenderFib->append_child($qtiResponseLabel);
00916 $qtiResponseStr->append_child($qtiRenderFib);
00917 $qtiFlow->append_child($qtiResponseStr);
00918 }
00919 }
00920 }
00921 $qtiPresentation->append_child($qtiFlow);
00922 $qtiIdent->append_child($qtiPresentation);
00923
00924
00925 $qtiResprocessing = $this->domxml->create_element("resprocessing");
00926 $qtiOutcomes = $this->domxml->create_element("outcomes");
00927 $qtiDecvar = $this->domxml->create_element("decvar");
00928 $qtiOutcomes->append_child($qtiDecvar);
00929 $qtiResprocessing->append_child($qtiOutcomes);
00930
00931 for ($i = 0; $i < $this->get_gap_count(); $i++)
00932 {
00933 $gap = $this->get_gap($i);
00934 if ($gap[0]->get_cloze_type() == CLOZE_SELECT)
00935 {
00936 foreach ($gap as $index => $answer)
00937 {
00938 $qtiRespcondition = $this->domxml->create_element("respcondition");
00939 $qtiRespcondition->set_attribute("continue", "Yes");
00940
00941 $qtiConditionvar = $this->domxml->create_element("conditionvar");
00942
00943 if (!$answer->isStateSet())
00944 {
00945 $qtinot = $this->domxml->create_element("not");
00946 }
00947
00948 $qtiVarequal = $this->domxml->create_element("varequal");
00949 $qtiVarequal->set_attribute("respident", "gap_$i");
00950 $qtiVarequalText = $this->domxml->create_text_node($answer->get_answertext());
00951 $qtiVarequal->append_child($qtiVarequalText);
00952 if (!$answer->isStateSet())
00953 {
00954 $qtiConditionvar->append_child($qtinot);
00955 $qtinot->append_child($qtiVarequal);
00956 }
00957 else
00958 {
00959 $qtiConditionvar->append_child($qtiVarequal);
00960 }
00961
00962 $qtiSetvar = $this->domxml->create_element("setvar");
00963 $qtiSetvar->set_attribute("action", "Add");
00964 $qtiSetvarText = $this->domxml->create_text_node($answer->get_points());
00965 $qtiSetvar->append_child($qtiSetvarText);
00966
00967 $qtiDisplayfeedback = $this->domxml->create_element("displayfeedback");
00968 $qtiDisplayfeedback->set_attribute("feedbacktype", "Response");
00969 $linkrefid = "";
00970 if ($answer->isStateSet())
00971 {
00972 $linkrefid = "$i" . "_True";
00973 }
00974 else
00975 {
00976 $linkrefid = "$i" . "_False_$index";
00977 }
00978 $qtiDisplayfeedback->set_attribute("linkrefid", $linkrefid);
00979 $qtiRespcondition->append_child($qtiConditionvar);
00980 $qtiRespcondition->append_child($qtiSetvar);
00981 $qtiRespcondition->append_child($qtiDisplayfeedback);
00982 $qtiResprocessing->append_child($qtiRespcondition);
00983 }
00984 }
00985 else
00986 {
00987 foreach ($gap as $index => $answer)
00988 {
00989 $qtiRespcondition = $this->domxml->create_element("respcondition");
00990 $qtiRespcondition->set_attribute("continue", "Yes");
00991
00992 $qtiConditionvar = $this->domxml->create_element("conditionvar");
00993 $qtiVarequal = $this->domxml->create_element("varequal");
00994 $qtiVarequal->set_attribute("respident", "gap_$i");
00995 $qtiVarequalText = $this->domxml->create_text_node($answer->get_answertext());
00996 $qtiVarequal->append_child($qtiVarequalText);
00997 $qtiConditionvar->append_child($qtiVarequal);
00998
00999 $qtiSetvar = $this->domxml->create_element("setvar");
01000 $qtiSetvar->set_attribute("action", "Add");
01001 $qtiSetvarText = $this->domxml->create_text_node($answer->get_points());
01002 $qtiSetvar->append_child($qtiSetvarText);
01003
01004 $qtiDisplayfeedback = $this->domxml->create_element("displayfeedback");
01005 $qtiDisplayfeedback->set_attribute("feedbacktype", "Response");
01006 $qtiDisplayfeedback->set_attribute("linkrefid", "$i" . "_True_$index");
01007 $qtiRespcondition->append_child($qtiConditionvar);
01008 $qtiRespcondition->append_child($qtiSetvar);
01009 $qtiRespcondition->append_child($qtiDisplayfeedback);
01010 $qtiResprocessing->append_child($qtiRespcondition);
01011 }
01012 }
01013 }
01014 $qtiIdent->append_child($qtiResprocessing);
01015
01016
01017 for ($i = 0; $i < $this->get_gap_count(); $i++)
01018 {
01019 $gap = $this->get_gap($i);
01020 if ($gap[0]->get_cloze_type() == CLOZE_SELECT)
01021 {
01022 foreach ($gap as $index => $answer)
01023 {
01024 $qtiItemfeedback = $this->domxml->create_element("itemfeedback");
01025 $linkrefid = "";
01026 if ($answer->isStateSet())
01027 {
01028 $linkrefid = "$i" . "_True";
01029 }
01030 else
01031 {
01032 $linkrefid = "$i" . "_False_$index";
01033 }
01034 $qtiItemfeedback->set_attribute("ident", $linkrefid);
01035 $qtiItemfeedback->set_attribute("view", "All");
01036
01037 $qtiFlowmat = $this->domxml->create_element("flow_mat");
01038 $qtiMaterial = $this->domxml->create_element("material");
01039 $qtiMattext = $this->domxml->create_element("mattext");
01040
01041 $qtiMattextText = $this->domxml->create_text_node("");
01042 $qtiMattext->append_child($qtiMattextText);
01043 $qtiMaterial->append_child($qtiMattext);
01044 $qtiFlowmat->append_child($qtiMaterial);
01045 $qtiItemfeedback->append_child($qtiFlowmat);
01046 $qtiIdent->append_child($qtiItemfeedback);
01047 }
01048 }
01049 else
01050 {
01051 foreach ($gap as $index => $answer)
01052 {
01053 $qtiItemfeedback = $this->domxml->create_element("itemfeedback");
01054 $linkrefid = "";
01055 if ($answer->isStateSet())
01056 {
01057 $linkrefid = "$i" . "_True_$index";
01058 }
01059 else
01060 {
01061 $linkrefid = "$i" . "_False_$index";
01062 }
01063 $qtiItemfeedback->set_attribute("ident", $linkrefid);
01064 $qtiItemfeedback->set_attribute("view", "All");
01065
01066 $qtiFlowmat = $this->domxml->create_element("flow_mat");
01067 $qtiMaterial = $this->domxml->create_element("material");
01068 $qtiMattext = $this->domxml->create_element("mattext");
01069
01070 $qtiMattextText = $this->domxml->create_text_node("");
01071 $qtiMattext->append_child($qtiMattextText);
01072 $qtiMaterial->append_child($qtiMattext);
01073 $qtiFlowmat->append_child($qtiMaterial);
01074 $qtiItemfeedback->append_child($qtiFlowmat);
01075 $qtiIdent->append_child($qtiItemfeedback);
01076 }
01077 }
01078 }
01079
01080 $xml = $this->domxml->dump_mem(true);
01081 if (!$a_include_header)
01082 {
01083 $pos = strpos($xml, "?>");
01084 $xml = substr($xml, $pos + 2);
01085 }
01086
01087 return $xml;
01088
01089 }
01090
01102 function set_cloze_text($cloze_text = "")
01103 {
01104 $this->gaps = array();
01105 $this->cloze_text =& $cloze_text;
01106 $close = $this->createCloseTextArray();
01107 if (count($close))
01108 {
01109 foreach ($close["gaps"] as $key => $value)
01110 {
01111 if (strcmp(strtolower($value["params"]["type"]), "select") == 0)
01112 {
01113 $type = CLOZE_SELECT;
01114 }
01115 else
01116 {
01117 $type = CLOZE_TEXT;
01118 }
01119 if ($type == CLOZE_TEXT)
01120 {
01121 $default_state = 1;
01122 }
01123 else
01124 {
01125 $default_state = 0;
01126 }
01127 $name = $value["params"]["name"];
01128 if (strcmp(strtolower($value["params"]["shuffle"]), "no") == 0)
01129 {
01130 $shuffle = 0;
01131 }
01132 else
01133 {
01134 $shuffle = 1;
01135 }
01136 $answer_array = array();
01137 foreach ($value["text"] as $index => $textvalue)
01138 {
01139 if (preg_match("/\d+/", $index))
01140 {
01141 $textvalue = str_replace("\,", ",", $textvalue);
01142 array_push($answer_array, new ASS_AnswerCloze($textvalue, 0, $index, $default_state, $type, $name, $shuffle));
01143 }
01144 }
01145 array_push($this->gaps, $answer_array);
01146 }
01147 }
01148 }
01149
01159 function get_cloze_text() {
01160 return $this->cloze_text;
01161 }
01162
01172 function get_start_tag() {
01173 return $this->start_tag;
01174 }
01175
01185 function get_end_tag() {
01186 return $this->end_tag;
01187 }
01188
01198 function set_start_tag($start_tag = "<gap>") {
01199 $this->start_tag = $start_tag;
01200 }
01201
01202
01212 function set_end_tag($end_tag = "</gap>") {
01213 $this->end_tag = $end_tag;
01214 }
01215
01224 function rebuild_cloze_text()
01225 {
01226 $close =& $this->createCloseTextArray();
01227 if (count($close))
01228 {
01229 for ($i = 0; $i < count($this->gaps); $i++)
01230 {
01231 $gaptext = $this->get_gap_text_list($i);
01232 $textparams = preg_split("/(?<!\\\\),/", $gaptext);
01233 $close["gaps"][$i]["text"] = array();
01234 $close["gaps"][$i]["text"]["text"] = $gaptext;
01235 foreach ($textparams as $key => $value)
01236 {
01237 $close["gaps"][$i]["text"][$key] = $value;
01238 }
01239 }
01240 }
01241 $this->createCloseTextFromArray($close);
01242 }
01243
01255 function get_gap($index = 0) {
01256 if ($index < 0) return array();
01257 if (count($this->gaps) < 1) return array();
01258 if ($index >= count($this->gaps)) return array();
01259 return $this->gaps[$index];
01260 }
01261
01271 function get_gap_count() {
01272 return count($this->gaps);
01273 }
01274
01287 function get_gap_text_list($index = 0, $separator = ",") {
01288 if ($index < 0) return "";
01289 if (count($this->gaps) < 1) return "";
01290 if ($index >= count($this->gaps)) return "";
01291 $result = array();
01292 foreach ($this->gaps[$index] as $key => $value) {
01293 array_push($result, str_replace(",", "\,", $value->get_answertext()));
01294 }
01295 return join($separator, $result);
01296 }
01306 function get_gap_text_count($index = 0) {
01307 if ($index < 0) return 0;
01308 if (count($this->gaps) < 1) return 0;
01309 if ($index >= count($this->gaps)) return 0;
01310 return count($this->gaps[$index]);
01311 }
01322 function delete_gap($index = 0) {
01323 if ($index < 0) return;
01324 if (count($this->gaps) < 1) return;
01325 if ($index >= count($this->gaps)) return;
01326 $close = $this->createCloseTextArray();
01327 unset($close["gaps"][$index]);
01328 $this->createCloseTextFromArray($close);
01329 unset($this->gaps[$index]);
01330 $this->gaps = array_values($this->gaps);
01331 }
01332
01341 function flush_gaps() {
01342 $this->gaps = array();
01343 }
01344
01356 function delete_answertext_by_index($gap_index = 0, $answertext_index = 0) {
01357 if ($gap_index < 0) return;
01358 if (count($this->gaps) < 1) return;
01359 if ($gap_index >= count($this->gaps)) return;
01360 $old_text = $this->get_gap_text_list($gap_index);
01361 if (count($this->gaps[$gap_index]) == 1) {
01362 $this->delete_gap($gap_index);
01363 } else {
01364 $close = $this->createCloseTextArray();
01365 unset($this->gaps[$gap_index][$answertext_index]);
01366 $this->gaps[$gap_index] = array_values($this->gaps[$gap_index]);
01367 unset($close["gaps"][$gap_index]["text"][$answertext_index]);
01368 $this->createCloseTextFromArray($close);
01369 }
01370 }
01371
01384 function set_answertext($index = 0, $answertext_index = 0, $answertext = "", $add_gaptext=0) {
01385 $answertext = str_replace("\,", ",", $answertext);
01386 if ($add_gaptext == 1) {
01387 $arr = $this->gaps[$index][0];
01388 if (strlen($this->gaps[$index][count($this->gaps[$index])-1]->get_answertext()) != 0) {
01389 $default_state = 0;
01390 if ($arr->get_cloze_type() == CLOZE_TEXT)
01391 {
01392 $default_state = 1;
01393 }
01394 array_push($this->gaps[$index], new ASS_AnswerCloze($answertext, 0, count($this->gaps[$index]),
01395 $default_state, $arr->get_cloze_type(),
01396 $arr->get_name(), $arr->get_shuffle()));
01397 $this->rebuild_cloze_text();
01398 }
01399 return;
01400 }
01401 if ($index < 0) return;
01402 if (count($this->gaps) < 1) return;
01403 if ($index >= count($this->gaps)) return;
01404 if ($answertext_index < 0) return;
01405 if (count($this->gaps[$index]) < 1) return;
01406 if ($answertext_index >= count($this->gaps[$index])) return;
01407
01408
01409 if (strlen($answertext) == 0) {
01410
01411 $this->delete_answertext($index, $this->gaps[$index][$answertext_index]->get_answertext());
01412 } else {
01413 $this->gaps[$index][$answertext_index]->set_answertext($answertext);
01414 $this->rebuild_cloze_text();
01415 }
01416 }
01417
01426 function update_all_gap_params() {
01427 global $lng;
01428 $close = $this->createCloseTextArray();
01429 for ($i = 0; $i < $this->get_gap_count(); $i++)
01430 {
01431 $gaptext = $this->get_gap_text_list($i);
01432 if ($this->gaps[$i][0]->get_cloze_type() == CLOZE_TEXT)
01433 {
01434 $close["gaps"][$i]["params"]["type"] = "text";
01435 if (array_key_exists("shuffle", $close["gaps"][$i]["params"]))
01436 {
01437 unset($close["gaps"][$i]["params"]["shuffle"]);
01438 }
01439 }
01440 else
01441 {
01442 $close["gaps"][$i]["params"]["type"] = "select";
01443 if ($this->gaps[$i][0]->get_shuffle() == 0)
01444 {
01445 $close["gaps"][$i]["params"]["shuffle"] = "no";
01446 }
01447 else
01448 {
01449 $close["gaps"][$i]["params"]["shuffle"] = "yes";
01450 }
01451 }
01452 $name = $this->gaps[$i][0]->get_name();
01453 if (!$name)
01454 {
01455 $name = $this->lng->txt("gap") . " " . ($i+1);
01456 }
01457 $close["gaps"][$i]["params"]["name"] = $name;
01458 }
01459 $this->createCloseTextFromArray($close);
01460 }
01461
01472 function set_cloze_type($index, $cloze_type = CLOZE_TEXT) {
01473 if ($index < 0) return;
01474 if (count($this->gaps) < 1) return;
01475 if ($index >= count($this->gaps)) return;
01476 $close = $this->createCloseTextArray();
01477 foreach ($this->gaps[$index] as $key => $value) {
01478 $this->gaps[$index][$key]->set_cloze_type($cloze_type);
01479 $this->gaps[$index][$key]->setState(1);
01480 }
01481 if ($cloze_type == CLOZE_TEXT)
01482 {
01483 $type = "text";
01484 }
01485 else
01486 {
01487 $type = "select";
01488 }
01489 $close["gaps"][$index]["type"] = $type;
01490 $this->createCloseTextFromArray($close);
01491 }
01492
01504 function set_gap_points($index = 0, $points = 0.0) {
01505 if ($index < 0) return;
01506 if (count($this->gaps) < 1) return;
01507 if ($index >= count($this->gaps)) return;
01508 foreach ($this->gaps[$index] as $key => $value) {
01509 $this->gaps[$index][$key]->set_points($points);
01510 }
01511 }
01512
01524 function set_gap_shuffle($index = 0, $shuffle = 1) {
01525 if ($index < 0) return;
01526 if (count($this->gaps) < 1) return;
01527 if ($index >= count($this->gaps)) return;
01528 foreach ($this->gaps[$index] as $key => $value) {
01529 $this->gaps[$index][$key]->set_shuffle($shuffle);
01530 }
01531 }
01532
01533
01546 function set_single_answer_points($index_gaps = 0, $index_answerobject = 0, $points = 0.0) {
01547 if ($index_gaps < 0) return;
01548 if (count($this->gaps) < 1) return;
01549 if ($index_gaps >= count($this->gaps)) return;
01550 if ($index_answerobject < 0) return;
01551 if (count($this->gaps[$index_gaps]) < 1) return;
01552 if ($index_answerobject >= count($this->gaps[$index_gaps])) return;
01553 $this->gaps[$index_gaps][$index_answerobject]->set_points($points);
01554 }
01555
01568 function set_single_answer_state($index_gaps = 0, $index_answerobject = 0, $state = 0) {
01569 if ($index_gaps < 0) return;
01570 if (count($this->gaps) < 1) return;
01571 if ($index_gaps >= count($this->gaps)) return;
01572 if ($index_answerobject < 0) return;
01573 if (count($this->gaps[$index_gaps]) < 1) return;
01574 if ($index_answerobject >= count($this->gaps[$index_gaps])) return;
01575 $this->gaps[$index_gaps][$index_answerobject]->setState($state);
01576 }
01577
01589 function calculateReachedPoints($user_id, $test_id)
01590 {
01591 global $ilDB;
01592
01593 $found_value1 = array();
01594 $found_value2 = array();
01595 $query = sprintf("SELECT * FROM tst_solutions WHERE user_fi = %s AND test_fi = %s AND question_fi = %s",
01596 $ilDB->quote($user_id),
01597 $ilDB->quote($test_id),
01598 $ilDB->quote($this->getId())
01599 );
01600 $result = $ilDB->query($query);
01601 $user_result = array();
01602 while ($data = $result->fetchRow(DB_FETCHMODE_OBJECT)) {
01603 if (strcmp($data->value2, "") != 0)
01604 {
01605 $user_result[$data->value1] = array(
01606 "gap_id" => $data->value1,
01607 "value" => $data->value2
01608 );
01609 }
01610 }
01611 $points = 0;
01612 $counter = 0;
01613 foreach ($user_result as $gap_id => $value) {
01614 if ($this->gaps[$gap_id][0]->get_cloze_type() == CLOZE_TEXT)
01615 {
01616 $foundsolution = 0;
01617 foreach ($this->gaps[$gap_id] as $k => $v) {
01618 if ((strcmp(strtolower($v->get_answertext()), strtolower($value["value"])) == 0) && (!$foundsolution)) {
01619 $points += $v->get_points();
01620 $foundsolution = 1;
01621 }
01622 }
01623 }
01624 else
01625 {
01626 if ($value["value"] >= 0)
01627 {
01628 foreach ($this->gaps[$gap_id] as $answerkey => $answer)
01629 {
01630 if ($value["value"] == $answerkey)
01631 {
01632 $points += $answer->get_points();
01633 }
01634 }
01635 }
01636 }
01637 }
01638
01639
01640 $query = sprintf("SELECT * FROM tst_tests WHERE test_id = %s",
01641 $ilDB->quote($test_id)
01642 );
01643 $result = $ilDB->query($query);
01644 if ($result->numRows() == 1)
01645 {
01646 $row = $result->fetchRow(DB_FETCHMODE_ASSOC);
01647 if ($row["count_system"] == 1)
01648 {
01649 if ($points != $this->getMaximumPoints())
01650 {
01651 $points = 0;
01652 }
01653 }
01654 }
01655 else
01656 {
01657 $points = 0;
01658 }
01659 return $points;
01660 }
01661
01671 function getReachedInformation($user_id, $test_id) {
01672 $found_value1 = array();
01673 $found_value2 = array();
01674 $query = sprintf("SELECT * FROM tst_solutions WHERE user_fi = %s AND test_fi = %s AND question_fi = %s",
01675 $this->ilias->db->quote($user_id),
01676 $this->ilias->db->quote($test_id),
01677 $this->ilias->db->quote($this->getId())
01678 );
01679 $result = $this->ilias->db->query($query);
01680 while ($data = $result->fetchRow(DB_FETCHMODE_OBJECT)) {
01681 array_push($found_value1, $data->value1);
01682 array_push($found_value2, $data->value2);
01683 }
01684 $counter = 1;
01685 $user_result = array();
01686 foreach ($found_value1 as $key => $value) {
01687 if ($this->gaps[$value][0]->get_cloze_type() == CLOZE_TEXT)
01688 {
01689 $solution = array(
01690 "gap" => "$counter",
01691 "points" => 0,
01692 "true" => 0,
01693 "value" => $found_value2[$key]
01694 );
01695 foreach ($this->gaps[$value] as $k => $v) {
01696 if (strcmp(strtolower($v->get_answertext()), strtolower($found_value2[$key])) == 0) {
01697 $solution = array(
01698 "gap" => "$counter",
01699 "points" => $v->get_points(),
01700 "true" => 1,
01701 "value" => $found_value2[$key]
01702 );
01703 }
01704 }
01705 }
01706 else
01707 {
01708 $solution = array(
01709 "gap" => "$counter",
01710 "points" => 0,
01711 "true" => 0,
01712 "value" => $found_value2[$key]
01713 );
01714 if ($this->gaps[$value][$found_value1[$key]]->isStateSet()) {
01715 $solution["points"] = $this->gaps[$value][$found_value1[$key]]->get_points();
01716 $solution["true"] = 1;
01717 }
01718 }
01719 $counter++;
01720 $user_result[$value] = $solution;
01721 }
01722 return $user_result;
01723 }
01724
01733 function getMaximumPoints() {
01734 $points = 0;
01735 foreach ($this->gaps as $key => $value) {
01736 if ($value[0]->get_cloze_type() == CLOZE_TEXT) {
01737 $points += $value[0]->get_points();
01738 } else {
01739 $points_arr = array("set" => 0, "unset" => 0);
01740 foreach ($value as $key2 => $value2) {
01741 if ($value2->get_points() > $points_arr["set"])
01742 {
01743 $points_arr["set"] = $value2->get_points();
01744 }
01745 }
01746 $points += $points_arr["set"];
01747 }
01748 }
01749 return $points;
01750 }
01751
01762 function saveWorkingData($test_id, $limit_to = LIMIT_NO_LIMIT) {
01763 global $ilDB;
01764 global $ilUser;
01765 $db =& $ilDB->db;
01766
01767 $query = sprintf("DELETE FROM tst_solutions WHERE user_fi = %s AND test_fi = %s AND question_fi = %s",
01768 $db->quote($ilUser->id),
01769 $db->quote($test_id),
01770 $db->quote($this->getId())
01771 );
01772 $result = $db->query($query);
01773
01774 foreach ($_POST as $key => $value) {
01775 if (preg_match("/^gap_(\d+)/", $key, $matches)) {
01776 $query = sprintf("INSERT INTO tst_solutions (solution_id, user_fi, test_fi, question_fi, value1, value2, TIMESTAMP) VALUES (NULL, %s, %s, %s, %s, %s, NULL)",
01777 $db->quote($ilUser->id),
01778 $db->quote($test_id),
01779 $db->quote($this->getId()),
01780 $db->quote($matches[1]),
01781 $db->quote(ilUtil::stripSlashes($value))
01782 );
01783 $result = $db->query($query);
01784 }
01785 }
01786 parent::saveWorkingData($test_id);
01787 return true;
01788 }
01789
01790 function syncWithOriginal()
01791 {
01792 global $ilias;
01793 if ($this->original_id)
01794 {
01795 $complete = 0;
01796 if ($this->isComplete())
01797 {
01798 $complete = 1;
01799 }
01800 $db = & $ilias->db;
01801
01802 $estw_time = $this->getEstimatedWorkingTime();
01803 $estw_time = sprintf("%02d:%02d:%02d", $estw_time['h'], $estw_time['m'], $estw_time['s']);
01804
01805 $query = sprintf("UPDATE qpl_questions SET obj_fi = %s, title = %s, comment = %s, points = %s, author = %s, question_text = %s, working_time = %s, shuffle = %s, complete = %s WHERE question_id = %s",
01806 $db->quote($this->obj_id. ""),
01807 $db->quote($this->title . ""),
01808 $db->quote($this->comment . ""),
01809 $db->quote($this->getMaximumPoints() . ""),
01810 $db->quote($this->author . ""),
01811 $db->quote($this->cloze_text . ""),
01812 $db->quote($estw_time . ""),
01813 $db->quote($this->shuffle . ""),
01814 $db->quote($complete . ""),
01815 $db->quote($this->original_id . "")
01816 );
01817 $result = $db->query($query);
01818
01819 if ($result == DB_OK)
01820 {
01821
01822
01823 $query = sprintf("DELETE FROM qpl_answers WHERE question_fi = %s",
01824 $db->quote($this->original_id)
01825 );
01826 $result = $db->query($query);
01827
01828 foreach ($this->gaps as $key => $value)
01829 {
01830 foreach ($value as $answer_id => $answer_obj)
01831 {
01832 $query = sprintf("INSERT INTO qpl_answers (answer_id, question_fi, gap_id, answertext, points, aorder, cloze_type, name, shuffle, correctness, TIMESTAMP) VALUES (NULL, %s, %s, %s, %s, %s, %s, %s, %s, %s, NULL)",
01833 $db->quote($this->original_id . ""),
01834 $db->quote($key . ""),
01835 $db->quote($answer_obj->get_answertext() . ""),
01836 $db->quote($answer_obj->get_points() . ""),
01837 $db->quote($answer_obj->get_order() . ""),
01838 $db->quote($answer_obj->get_cloze_type() . ""),
01839 $db->quote($answer_obj->get_name() . ""),
01840 $db->quote($answer_obj->get_shuffle() . ""),
01841 $db->quote($answer_obj->getState() . "")
01842 );
01843 $answer_result = $db->query($query);
01844 }
01845 }
01846 }
01847 parent::syncWithOriginal();
01848 }
01849 }
01850
01859 function getQuestionType()
01860 {
01861 return 3;
01862 }
01863
01872 function getColumnSize($gap)
01873 {
01874 $size = 0;
01875 foreach ($gap as $answer)
01876 {
01877 $answertextsize = strlen($answer->get_answertext());
01878 if ($answertextsize > $size) $size = $answertextsize;
01879 }
01880 return $size;
01881 }
01882 }
01883
01884 ?>