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 "./assessment/classes/class.assQuestion.php";
00025 include_once "./assessment/classes/inc.AssessmentConstants.php";
00026
00037 class assMatchingQuestion extends assQuestion
00038 {
00046 var $question;
00047
00055 var $matchingpairs;
00056
00065 var $matching_type;
00066
00079 function assMatchingQuestion (
00080 $title = "",
00081 $comment = "",
00082 $author = "",
00083 $owner = -1,
00084 $question = "",
00085 $matching_type = MT_TERMS_DEFINITIONS
00086 )
00087 {
00088 $this->assQuestion($title, $comment, $author, $owner);
00089 $this->matchingpairs = array();
00090 $this->question = $question;
00091 $this->matching_type = $matching_type;
00092 }
00093
00102 function isComplete()
00103 {
00104 if (($this->title) and ($this->author) and ($this->question) and (count($this->matchingpairs)) and ($this->getMaximumPoints() > 0))
00105 {
00106 return true;
00107 }
00108 else
00109 {
00110 return false;
00111 }
00112 }
00113
00127 function fromXML(&$item, &$questionpool_id, &$tst_id, &$tst_object, &$question_counter, &$import_mapping)
00128 {
00129 global $ilUser;
00130
00131
00132 unset($_SESSION["import_mob_xhtml"]);
00133 $presentation = $item->getPresentation();
00134 $duration = $item->getDuration();
00135 $shuffle = 0;
00136 $now = getdate();
00137 $created = sprintf("%04d%02d%02d%02d%02d%02d", $now['year'], $now['mon'], $now['mday'], $now['hours'], $now['minutes'], $now['seconds']);
00138 $terms = array();
00139 $matches = array();
00140 $foundimage = FALSE;
00141 foreach ($presentation->order as $entry)
00142 {
00143 switch ($entry["type"])
00144 {
00145 case "response":
00146 $response = $presentation->response[$entry["index"]];
00147 $rendertype = $response->getRenderType();
00148 switch (strtolower(get_class($rendertype)))
00149 {
00150 case "ilqtirenderchoice":
00151 $shuffle = $rendertype->getShuffle();
00152 $answerorder = 0;
00153 foreach ($rendertype->response_labels as $response_label)
00154 {
00155 $ident = $response_label->getIdent();
00156 $answertext = "";
00157 $answerimage = array();
00158 foreach ($response_label->material as $mat)
00159 {
00160 for ($m = 0; $m < $mat->getMaterialCount(); $m++)
00161 {
00162 $foundmat = $mat->getMaterial($m);
00163 if (strcmp($foundmat["type"], "mattext") == 0)
00164 {
00165 $answertext .= $foundmat["material"]->getContent();
00166 }
00167 if (strcmp($foundmat["type"], "matimage") == 0)
00168 {
00169 $foundimage = TRUE;
00170 $answerimage = array(
00171 "imagetype" => $foundmat["material"]->getImageType(),
00172 "label" => $foundmat["material"]->getLabel(),
00173 "content" => $foundmat["material"]->getContent()
00174 );
00175 }
00176 }
00177 }
00178 if (($response_label->getMatchMax() == 1) && (strlen($response_label->getMatchGroup())))
00179 {
00180 $terms[$ident] = array(
00181 "answertext" => $answertext,
00182 "answerimage" => $answerimage,
00183 "points" => 0,
00184 "answerorder" => $ident,
00185 "action" => ""
00186 );
00187 }
00188 else
00189 {
00190 $matches[$ident] = array(
00191 "answertext" => $answertext,
00192 "answerimage" => $answerimage,
00193 "points" => 0,
00194 "matchingorder" => $ident,
00195 "action" => ""
00196 );
00197 }
00198 }
00199 break;
00200 }
00201 break;
00202 }
00203 }
00204 $responses = array();
00205 foreach ($item->resprocessing as $resprocessing)
00206 {
00207 foreach ($resprocessing->respcondition as $respcondition)
00208 {
00209 $subset = array();
00210 $correctness = 1;
00211 $conditionvar = $respcondition->getConditionvar();
00212 foreach ($conditionvar->order as $order)
00213 {
00214 switch ($order["field"])
00215 {
00216 case "varsubset":
00217 $subset = split(",", $conditionvar->varsubset[$order["index"]]->getContent());
00218 break;
00219 }
00220 }
00221 foreach ($respcondition->setvar as $setvar)
00222 {
00223 array_push($responses, array("subset" => $subset, "action" => $setvar->getAction(), "points" => $setvar->getContent()));
00224 }
00225 }
00226 }
00227 $type = 1;
00228 if ($foundimage)
00229 {
00230 $type = 0;
00231 }
00232 $this->setTitle($item->getTitle());
00233 $this->setComment($item->getComment());
00234 $this->setAuthor($item->getAuthor());
00235 $this->setOwner($ilUser->getId());
00236 $this->setQuestion($this->QTIMaterialToString($item->getQuestiontext()));
00237 $this->setMatchingType($type);
00238 $this->setObjId($questionpool_id);
00239 $this->setEstimatedWorkingTime($duration["h"], $duration["m"], $duration["s"]);
00240 $this->setShuffle($shuffle);
00241 foreach ($responses as $response)
00242 {
00243 $subset = $response["subset"];
00244 $term = array();
00245 $match = array();
00246 foreach ($subset as $ident)
00247 {
00248 if (array_key_exists($ident, $terms))
00249 {
00250 $term = $terms[$ident];
00251 }
00252 if (array_key_exists($ident, $matches))
00253 {
00254 $match = $matches[$ident];
00255 }
00256 }
00257 if ($type == 0)
00258 {
00259 $this->addMatchingPair($match["answertext"], $response["points"], $match["matchingorder"], $term["answerimage"]["label"], $term["answerorder"]);
00260 }
00261 else
00262 {
00263 $this->addMatchingPair($match["answertext"], $response["points"], $match["matchingorder"], $term["answertext"], $term["answerorder"]);
00264 }
00265 }
00266 $this->saveToDb();
00267 if (count($item->suggested_solutions))
00268 {
00269 foreach ($item->suggested_solutions as $suggested_solution)
00270 {
00271 $this->setSuggestedSolution($suggested_solution["solution"]->getContent(), $suggested_solution["gap_index"], true);
00272 }
00273 $this->saveToDb();
00274 }
00275 foreach ($responses as $response)
00276 {
00277 $subset = $response["subset"];
00278 $term = array();
00279 $match = array();
00280 foreach ($subset as $ident)
00281 {
00282 if (array_key_exists($ident, $terms))
00283 {
00284 $term = $terms[$ident];
00285 }
00286 if (array_key_exists($ident, $matches))
00287 {
00288 $match = $matches[$ident];
00289 }
00290 }
00291 if ($type == 0)
00292 {
00293 $image =& base64_decode($term["answerimage"]["content"]);
00294 $imagepath = $this->getImagePath();
00295 include_once "./classes/class.ilUtil.php";
00296 if (!file_exists($imagepath))
00297 {
00298 ilUtil::makeDirParents($imagepath);
00299 }
00300 $imagepath .= $term["answerimage"]["label"];
00301 $fh = fopen($imagepath, "wb");
00302 if ($fh == false)
00303 {
00304
00305
00306
00307 }
00308 else
00309 {
00310 $imagefile = fwrite($fh, $image);
00311 fclose($fh);
00312 }
00313
00314 $thumbpath = $imagepath . "." . "thumb.jpg";
00315 ilUtil::convertImage($imagepath, $thumbpath, "JPEG", 100);
00316 }
00317 }
00318
00319 if (is_array($_SESSION["import_mob_xhtml"]))
00320 {
00321 include_once "./content/classes/Media/class.ilObjMediaObject.php";
00322 include_once "./Services/RTE/classes/class.ilRTE.php";
00323 foreach ($_SESSION["import_mob_xhtml"] as $mob)
00324 {
00325 if ($tst_id > 0)
00326 {
00327 include_once "./assessment/classes/class.ilObjTest.php";
00328 $importfile = ilObjTest::_getImportDirectory() . "/" . $_SESSION["tst_import_subdir"] . "/" . $mob["uri"];
00329 }
00330 else
00331 {
00332 include_once "./assessment/classes/class.ilObjQuestionPool.php";
00333 $importfile = ilObjQuestionPool::_getImportDirectory() . "/" . $_SESSION["qpl_import_subdir"] . "/" . $mob["uri"];
00334 }
00335 $media_object =& ilObjMediaObject::_saveTempFileAsMediaObject(basename($importfile), $importfile, FALSE);
00336 ilObjMediaObject::_saveUsage($media_object->getId(), "qpl:html", $this->getId());
00337 $this->setQuestion(ilRTE::_replaceMediaObjectImageSrc(str_replace("src=\"" . $mob["mob"] . "\"", "src=\"" . "il_" . IL_INST_ID . "_mob_" . $media_object->getId() . "\"", $this->getQuestion()), 1));
00338 }
00339 $this->saveToDb();
00340 }
00341 if ($tst_id > 0)
00342 {
00343 $q_1_id = $this->getId();
00344 $question_id = $this->duplicate(true);
00345 $tst_object->questions[$question_counter++] = $question_id;
00346 $import_mapping[$item->getIdent()] = array("pool" => $q_1_id, "test" => $question_id);
00347 }
00348 else
00349 {
00350 $import_mapping[$item->getIdent()] = array("pool" => $this->getId(), "test" => 0);
00351 }
00352
00353 }
00354
00364 function to_xml($a_include_header = true, $a_include_binary = true, $a_shuffle = false, $test_output = false, $force_image_references = false)
00365 {
00366 include_once("./classes/class.ilXmlWriter.php");
00367 $a_xml_writer = new ilXmlWriter;
00368
00369 $a_xml_writer->xmlHeader();
00370 $a_xml_writer->xmlStartTag("questestinterop");
00371 $attrs = array(
00372 "ident" => "il_".IL_INST_ID."_qst_".$this->getId(),
00373 "title" => $this->getTitle()
00374 );
00375 $a_xml_writer->xmlStartTag("item", $attrs);
00376
00377 $a_xml_writer->xmlElement("qticomment", NULL, $this->getComment());
00378
00379 $workingtime = $this->getEstimatedWorkingTime();
00380 $duration = sprintf("P0Y0M0DT%dH%dM%dS", $workingtime["h"], $workingtime["m"], $workingtime["s"]);
00381 $a_xml_writer->xmlElement("duration", NULL, $duration);
00382
00383 $a_xml_writer->xmlStartTag("itemmetadata");
00384 $a_xml_writer->xmlStartTag("qtimetadata");
00385 $a_xml_writer->xmlStartTag("qtimetadatafield");
00386 $a_xml_writer->xmlElement("fieldlabel", NULL, "ILIAS_VERSION");
00387 $a_xml_writer->xmlElement("fieldentry", NULL, $this->ilias->getSetting("ilias_version"));
00388 $a_xml_writer->xmlEndTag("qtimetadatafield");
00389 $a_xml_writer->xmlStartTag("qtimetadatafield");
00390 $a_xml_writer->xmlElement("fieldlabel", NULL, "QUESTIONTYPE");
00391 $a_xml_writer->xmlElement("fieldentry", NULL, MATCHING_QUESTION_IDENTIFIER);
00392 $a_xml_writer->xmlEndTag("qtimetadatafield");
00393 $a_xml_writer->xmlStartTag("qtimetadatafield");
00394 $a_xml_writer->xmlElement("fieldlabel", NULL, "AUTHOR");
00395 $a_xml_writer->xmlElement("fieldentry", NULL, $this->getAuthor());
00396 $a_xml_writer->xmlEndTag("qtimetadatafield");
00397 $a_xml_writer->xmlEndTag("qtimetadata");
00398 $a_xml_writer->xmlEndTag("itemmetadata");
00399
00400
00401 $attrs = array(
00402 "label" => $this->getTitle()
00403 );
00404 $a_xml_writer->xmlStartTag("presentation", $attrs);
00405
00406 $a_xml_writer->xmlStartTag("flow");
00407
00408 $this->addQTIMaterial($a_xml_writer, $this->getQuestion());
00409
00410 $attrs = array();
00411 if ($this->get_matching_type() == MT_TERMS_PICTURES)
00412 {
00413 $attrs = array(
00414 "ident" => "MQP",
00415 "rcardinality" => "Multiple"
00416 );
00417 }
00418 else
00419 {
00420 $attrs = array(
00421 "ident" => "MQT",
00422 "rcardinality" => "Multiple"
00423 );
00424 }
00425 if ($this->getOutputType() == OUTPUT_JAVASCRIPT)
00426 {
00427 $attrs["output"] = "javascript";
00428 }
00429 $a_xml_writer->xmlStartTag("response_grp", $attrs);
00430 $solution = $this->getSuggestedSolution(0);
00431 if (count($solution))
00432 {
00433 if (preg_match("/il_(\d*?)_(\w+)_(\d+)/", $solution["internal_link"], $matches))
00434 {
00435 $a_xml_writer->xmlStartTag("material");
00436 $intlink = "il_" . IL_INST_ID . "_" . $matches[2] . "_" . $matches[3];
00437 if (strcmp($matches[1], "") != 0)
00438 {
00439 $intlink = $solution["internal_link"];
00440 }
00441 $attrs = array(
00442 "label" => "suggested_solution"
00443 );
00444 $a_xml_writer->xmlElement("mattext", $attrs, $intlink);
00445 $a_xml_writer->xmlEndTag("material");
00446 }
00447 }
00448
00449 $attrs = array();
00450 if ($this->getShuffle())
00451 {
00452 $attrs = array(
00453 "shuffle" => "Yes"
00454 );
00455 }
00456 else
00457 {
00458 $attrs = array(
00459 "shuffle" => "No"
00460 );
00461 }
00462 $a_xml_writer->xmlStartTag("render_choice", $attrs);
00463
00464 $matchingtext_orders = array();
00465 foreach ($this->matchingpairs as $index => $matchingpair)
00466 {
00467 array_push($matchingtext_orders, $matchingpair->getTermId());
00468 }
00469
00470
00471 $pkeys = array_keys($this->matchingpairs);
00472 if ($this->getshuffle() && $a_shuffle)
00473 {
00474 $pkeys = $this->pcArrayShuffle($pkeys);
00475 }
00476
00477 foreach ($pkeys as $index)
00478 {
00479 $matchingpair = $this->matchingpairs[$index];
00480 $attrs = array(
00481 "ident" => $matchingpair->getDefinitionId(),
00482 "match_max" => "1",
00483 "match_group" => join($matchingtext_orders, ",")
00484 );
00485 $a_xml_writer->xmlStartTag("response_label", $attrs);
00486 if ($this->get_matching_type() == MT_TERMS_PICTURES)
00487 {
00488 $a_xml_writer->xmlStartTag("material");
00489 if ($force_image_references)
00490 {
00491 $attrs = array(
00492 "imagtype" => "image/jpeg",
00493 "label" => $matchingpair->getPicture(),
00494 "uri" => $this->getImagePathWeb() . $matchingpair->getPicture()
00495 );
00496 $a_xml_writer->xmlElement("matimage", $attrs);
00497 }
00498 else
00499 {
00500 $imagepath = $this->getImagePath() . $matchingpair->getPicture();
00501 $fh = @fopen($imagepath, "rb");
00502 if ($fh != false)
00503 {
00504 $imagefile = fread($fh, filesize($imagepath));
00505 fclose($fh);
00506 $base64 = base64_encode($imagefile);
00507 $attrs = array(
00508 "imagtype" => "image/jpeg",
00509 "label" => $matchingpair->getPicture(),
00510 "embedded" => "base64"
00511 );
00512 $a_xml_writer->xmlElement("matimage", $attrs, $base64, FALSE, FALSE);
00513 }
00514 }
00515 $a_xml_writer->xmlEndTag("material");
00516 }
00517 else
00518 {
00519 $a_xml_writer->xmlStartTag("material");
00520 $this->addQTIMaterial($a_xml_writer, $matchingpair->getDefinition(), TRUE, FALSE);
00521 $a_xml_writer->xmlEndTag("material");
00522 }
00523 $a_xml_writer->xmlEndTag("response_label");
00524 }
00525
00526 if ($this->getshuffle() && $a_shuffle)
00527 {
00528 $pkeys = $this->pcArrayShuffle($pkeys);
00529 }
00530
00531 foreach ($pkeys as $index)
00532 {
00533 $matchingpair = $this->matchingpairs[$index];
00534 $attrs = array(
00535 "ident" => $matchingpair->getTermId()
00536 );
00537 $a_xml_writer->xmlStartTag("response_label", $attrs);
00538 $a_xml_writer->xmlStartTag("material");
00539 $attrs = array(
00540 "texttype" => "text/plain"
00541 );
00542 if ($this->isHTML($matchingpair->getTerm()))
00543 {
00544 $attrs["texttype"] = "text/xhtml";
00545 }
00546 $a_xml_writer->xmlElement("mattext", $attrs, $matchingpair->getTerm());
00547 $a_xml_writer->xmlEndTag("material");
00548 $a_xml_writer->xmlEndTag("response_label");
00549 }
00550 $a_xml_writer->xmlEndTag("render_choice");
00551 $a_xml_writer->xmlEndTag("response_grp");
00552 $a_xml_writer->xmlEndTag("flow");
00553 $a_xml_writer->xmlEndTag("presentation");
00554
00555
00556 $a_xml_writer->xmlStartTag("resprocessing");
00557 $a_xml_writer->xmlStartTag("outcomes");
00558 $a_xml_writer->xmlStartTag("decvar");
00559 $a_xml_writer->xmlEndTag("decvar");
00560 $a_xml_writer->xmlEndTag("outcomes");
00561
00562 foreach ($this->matchingpairs as $index => $matchingpair)
00563 {
00564 $attrs = array(
00565 "continue" => "Yes"
00566 );
00567 $a_xml_writer->xmlStartTag("respcondition", $attrs);
00568
00569 $a_xml_writer->xmlStartTag("conditionvar");
00570 $attrs = array();
00571 if ($this->get_matching_type() == MT_TERMS_PICTURES)
00572 {
00573 $attrs = array(
00574 "respident" => "MQP"
00575 );
00576 }
00577 else
00578 {
00579 $attrs = array(
00580 "respident" => "MQT"
00581 );
00582 }
00583 $a_xml_writer->xmlElement("varsubset", $attrs, $matchingpair->getTermId() . "," . $matchingpair->getDefinitionId());
00584 $a_xml_writer->xmlEndTag("conditionvar");
00585
00586
00587 $attrs = array(
00588 "action" => "Add"
00589 );
00590 $a_xml_writer->xmlElement("setvar", $attrs, $matchingpair->getPoints());
00591
00592 $attrs = array(
00593 "feedbacktype" => "Response",
00594 "linkrefid" => "correct_" . $matchingpair->getTermId() . "_" . $matchingpair->getDefinitionId()
00595 );
00596 $a_xml_writer->xmlElement("displayfeedback", $attrs);
00597 $a_xml_writer->xmlEndTag("respcondition");
00598 }
00599 $a_xml_writer->xmlEndTag("resprocessing");
00600
00601
00602 foreach ($this->matchingpairs as $index => $matchingpair)
00603 {
00604 $attrs = array(
00605 "ident" => "correct_" . $matchingpair->getTermId() . "_" . $matchingpair->getDefinitionId(),
00606 "view" => "All"
00607 );
00608 $a_xml_writer->xmlStartTag("itemfeedback", $attrs);
00609
00610 $a_xml_writer->xmlStartTag("flow_mat");
00611 $a_xml_writer->xmlStartTag("material");
00612 $a_xml_writer->xmlElement("mattext");
00613 $a_xml_writer->xmlEndTag("material");
00614 $a_xml_writer->xmlEndTag("flow_mat");
00615 $a_xml_writer->xmlEndTag("itemfeedback");
00616 }
00617 $a_xml_writer->xmlEndTag("item");
00618 $a_xml_writer->xmlEndTag("questestinterop");
00619
00620 $xml = $a_xml_writer->xmlDumpMem(FALSE);
00621 if (!$a_include_header)
00622 {
00623 $pos = strpos($xml, "?>");
00624 $xml = substr($xml, $pos + 2);
00625 }
00626 return $xml;
00627 }
00628
00637 function saveToDb($original_id = "")
00638 {
00639 global $ilDB;
00640
00641 $complete = 0;
00642 if ($this->isComplete())
00643 {
00644 $complete = 1;
00645 }
00646 $estw_time = $this->getEstimatedWorkingTime();
00647 $estw_time = sprintf("%02d:%02d:%02d", $estw_time['h'], $estw_time['m'], $estw_time['s']);
00648
00649 if ($original_id)
00650 {
00651 $original_id = $ilDB->quote($original_id);
00652 }
00653 else
00654 {
00655 $original_id = "NULL";
00656 }
00657
00658
00659 include_once("./Services/RTE/classes/class.ilRTE.php");
00660 ilRTE::_cleanupMediaObjectUsage($this->question, "qpl:html",
00661 $this->getId());
00662
00663 if ($this->id == -1)
00664 {
00665
00666 $now = getdate();
00667 $question_type = $this->getQuestionType();
00668 $created = sprintf("%04d%02d%02d%02d%02d%02d", $now['year'], $now['mon'], $now['mday'], $now['hours'], $now['minutes'], $now['seconds']);
00669 $query = sprintf("INSERT INTO qpl_questions (question_id, question_type_fi, obj_fi, title, comment, author, owner, question_text, working_time, points, complete, created, original_id, TIMESTAMP) VALUES (NULL, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, NULL)",
00670 $ilDB->quote($question_type. ""),
00671 $ilDB->quote($this->obj_id. ""),
00672 $ilDB->quote($this->title. ""),
00673 $ilDB->quote($this->comment. ""),
00674 $ilDB->quote($this->author. ""),
00675 $ilDB->quote($this->owner. ""),
00676 $ilDB->quote(ilRTE::_replaceMediaObjectImageSrc($this->question, 0)),
00677 $ilDB->quote($estw_time. ""),
00678 $ilDB->quote($this->getMaximumPoints() . ""),
00679 $ilDB->quote($complete. ""),
00680 $ilDB->quote($created. ""),
00681 $original_id
00682 );
00683
00684 $result = $ilDB->query($query);
00685 if ($result == DB_OK)
00686 {
00687 $this->id = $ilDB->getLastInsertId();
00688 $query = sprintf("INSERT INTO qpl_question_matching (question_fi, shuffle, matching_type) VALUES (%s, %s, %s)",
00689 $ilDB->quote($this->id . ""),
00690 $ilDB->quote($this->shuffle . ""),
00691 $ilDB->quote($this->matching_type. "")
00692 );
00693 $ilDB->query($query);
00694
00695
00696 $this->createPageObject();
00697
00698
00699 if ($this->getTestId() > 0)
00700 {
00701 $this->insertIntoTest($this->getTestId());
00702 }
00703 }
00704 }
00705 else
00706 {
00707
00708 $query = sprintf("UPDATE qpl_questions SET obj_fi = %s, title = %s, comment = %s, author = %s, question_text = %s, working_time=%s, points = %s, complete = %s WHERE question_id = %s",
00709 $ilDB->quote($this->obj_id. ""),
00710 $ilDB->quote($this->title. ""),
00711 $ilDB->quote($this->comment. ""),
00712 $ilDB->quote($this->author. ""),
00713 $ilDB->quote(ilRTE::_replaceMediaObjectImageSrc($this->question, 0)),
00714 $ilDB->quote($estw_time. ""),
00715 $ilDB->quote($this->getMaximumPoints() . ""),
00716 $ilDB->quote($complete. ""),
00717 $ilDB->quote($this->id. "")
00718 );
00719 $result = $ilDB->query($query);
00720 $query = sprintf("UPDATE qpl_question_matching SET shuffle = %s, matching_type = %s WHERE question_fi = %s",
00721 $ilDB->quote($this->shuffle . ""),
00722 $ilDB->quote($this->matching_type. ""),
00723 $ilDB->quote($this->id . "")
00724 );
00725 $result = $ilDB->query($query);
00726 }
00727
00728 if ($result == DB_OK)
00729 {
00730
00731
00732 $query = sprintf("DELETE FROM qpl_answer_matching WHERE question_fi = %s",
00733 $ilDB->quote($this->id)
00734 );
00735 $result = $ilDB->query($query);
00736
00737
00738 foreach ($this->matchingpairs as $key => $value)
00739 {
00740 $matching_obj = $this->matchingpairs[$key];
00741 $query = sprintf("INSERT INTO qpl_answer_matching (answer_id, question_fi, answertext, points, aorder, matchingtext, matching_order) VALUES (NULL, %s, %s, %s, %s, %s, %s)",
00742 $ilDB->quote($this->id),
00743 $ilDB->quote($matching_obj->getTerm() . ""),
00744 $ilDB->quote($matching_obj->getPoints() . ""),
00745 $ilDB->quote($matching_obj->getTermId() . ""),
00746 $ilDB->quote($matching_obj->getDefinition() . ""),
00747 $ilDB->quote($matching_obj->getDefinitionId() . "")
00748 );
00749 $matching_result = $ilDB->query($query);
00750 }
00751 }
00752 parent::saveToDb($original_id);
00753 }
00754
00764 function loadFromDb($question_id)
00765 {
00766 global $ilDB;
00767
00768 $query = sprintf("SELECT qpl_questions.*, qpl_question_matching.* FROM qpl_questions, qpl_question_matching WHERE question_id = %s AND qpl_questions.question_id = qpl_question_matching.question_fi",
00769 $ilDB->quote($question_id)
00770 );
00771 $result = $ilDB->query($query);
00772 if (strcmp(strtolower(get_class($result)), db_result) == 0)
00773 {
00774 if ($result->numRows() == 1)
00775 {
00776 $data = $result->fetchRow(DB_FETCHMODE_OBJECT);
00777 $this->id = $question_id;
00778 $this->title = $data->title;
00779 $this->comment = $data->comment;
00780 $this->author = $data->author;
00781 $this->solution_hint = $data->solution_hint;
00782 $this->obj_id = $data->obj_fi;
00783 $this->original_id = $data->original_id;
00784 $this->owner = $data->owner;
00785 $this->matching_type = $data->matching_type;
00786 include_once("./Services/RTE/classes/class.ilRTE.php");
00787 $this->question = ilRTE::_replaceMediaObjectImageSrc($data->question_text, 1);
00788 $this->points = $data->points;
00789 $this->shuffle = $data->shuffle;
00790 $this->setEstimatedWorkingTime(substr($data->working_time, 0, 2), substr($data->working_time, 3, 2), substr($data->working_time, 6, 2));
00791 }
00792
00793 $query = sprintf("SELECT * FROM qpl_answer_matching WHERE question_fi = %s ORDER BY answer_id ASC",
00794 $ilDB->quote($question_id)
00795 );
00796 $result = $ilDB->query($query);
00797 include_once "./assessment/classes/class.assAnswerMatching.php";
00798 if (strcmp(strtolower(get_class($result)), db_result) == 0)
00799 {
00800 while ($data = $result->fetchRow(DB_FETCHMODE_OBJECT))
00801 {
00802 array_push($this->matchingpairs, new ASS_AnswerMatching($data->answertext, $data->points, $data->aorder, $data->matchingtext, $data->matching_order));
00803 }
00804 }
00805 }
00806 parent::loadFromDb($question_id);
00807 }
00808
00816 function addMatchingPair($answertext, $points, $answerorder, $matchingtext, $matchingorder)
00817 {
00818 include_once "./assessment/classes/class.assAnswerMatching.php";
00819 array_push($this->matchingpairs, new ASS_AnswerMatching($answertext, $points, $answerorder, $matchingtext, $matchingorder));
00820 }
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 ("./assessment/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->duplicateImages($this_id);
00870 return $clone->id;
00871 }
00872
00880 function copyObject($target_questionpool, $title = "")
00881 {
00882 if ($this->id <= 0)
00883 {
00884
00885 return;
00886 }
00887
00888 $clone = $this;
00889 include_once ("./assessment/classes/class.assQuestion.php");
00890 $original_id = assQuestion::_getOriginalId($this->id);
00891 $clone->id = -1;
00892 if ($title)
00893 {
00894 $clone->setTitle($title);
00895 }
00896 $source_questionpool = $this->getObjId();
00897 $clone->setObjId($target_questionpool);
00898 $clone->saveToDb();
00899
00900
00901 $clone->copyPageOfQuestion($original_id);
00902
00903 $clone->copyXHTMLMediaObjectsOfQuestion($original_id);
00904
00905
00906 $clone->copyImages($original_id, $source_questionpool);
00907 return $clone->id;
00908 }
00909
00910 function duplicateImages($question_id)
00911 {
00912 if ($this->get_matching_type() == MT_TERMS_PICTURES)
00913 {
00914 $imagepath = $this->getImagePath();
00915 $imagepath_original = str_replace("/$this->id/images", "/$question_id/images", $imagepath);
00916 if (!file_exists($imagepath))
00917 {
00918 ilUtil::makeDirParents($imagepath);
00919 }
00920 foreach ($this->matchingpairs as $answer)
00921 {
00922 $filename = $answer->getPicture();
00923 if (!copy($imagepath_original . $filename, $imagepath . $filename))
00924 {
00925 print "image could not be duplicated!!!! ";
00926 }
00927 if (!copy($imagepath_original . $filename . ".thumb.jpg", $imagepath . $filename . ".thumb.jpg"))
00928 {
00929 print "image thumbnail could not be duplicated!!!! ";
00930 }
00931 }
00932 }
00933 }
00934
00935 function copyImages($question_id, $source_questionpool)
00936 {
00937 if ($this->get_matching_type() == MT_TERMS_PICTURES)
00938 {
00939 $imagepath = $this->getImagePath();
00940 $imagepath_original = str_replace("/$this->id/images", "/$question_id/images", $imagepath);
00941 $imagepath_original = str_replace("/$this->obj_id/", "/$source_questionpool/", $imagepath_original);
00942 if (!file_exists($imagepath))
00943 {
00944 ilUtil::makeDirParents($imagepath);
00945 }
00946 foreach ($this->matchingpairs as $answer)
00947 {
00948 $filename = $answer->getPicture();
00949 if (!copy($imagepath_original . $filename, $imagepath . $filename))
00950 {
00951 print "image could not be duplicated!!!! ";
00952 }
00953 if (!copy($imagepath_original . $filename . ".thumb.jpg", $imagepath . $filename . ".thumb.jpg"))
00954 {
00955 print "image thumbnail could not be duplicated!!!! ";
00956 }
00957 }
00958 }
00959 }
00960
00970 function setQuestion($question = "")
00971 {
00972 $this->question = $question;
00973 }
00974
00984 function setMatchingType($matching_type = MT_TERMS_DEFINITIONS)
00985 {
00986 $this->matching_type = $matching_type;
00987 }
00988
00998 function getQuestion()
00999 {
01000 return $this->question;
01001 }
01002
01012 function get_matching_type()
01013 {
01014 return $this->matching_type;
01015 }
01016
01031 function add_matchingpair(
01032 $term = "",
01033 $picture_or_definition = "",
01034 $points = 0.0,
01035 $term_id = 0,
01036 $picture_or_definition_id = 0
01037 )
01038 {
01039
01040 if ($term_id == 0)
01041 {
01042 $term_id = $this->get_random_id();
01043 }
01044
01045 if ($picture_or_definition_id == 0)
01046 {
01047 $picture_or_definition_id = $this->get_random_id();
01048 }
01049 include_once "./assessment/classes/class.assAnswerMatching.php";
01050 $matchingpair = new ASS_AnswerMatching($term, $points, $term_id, $picture_or_definition, $picture_or_definition_id);
01051 array_push($this->matchingpairs, $matchingpair);
01052 }
01053
01065 function get_matchingpair($index = 0)
01066 {
01067 if ($index < 0)
01068 {
01069 return NULL;
01070 }
01071 if (count($this->matchingpairs) < 1)
01072 {
01073 return NULL;
01074 }
01075 if ($index >= count($this->matchingpairs))
01076 {
01077 return NULL;
01078 }
01079 return $this->matchingpairs[$index];
01080 }
01081
01092 function delete_matchingpair($index = 0)
01093 {
01094 if ($index < 0)
01095 {
01096 return;
01097 }
01098 if (count($this->matchingpairs) < 1)
01099 {
01100 return;
01101 }
01102 if ($index >= count($this->matchingpairs))
01103 {
01104 return;
01105 }
01106 unset($this->matchingpairs[$index]);
01107 $this->matchingpairs = array_values($this->matchingpairs);
01108 }
01109
01118 function flush_matchingpairs()
01119 {
01120 $this->matchingpairs = array();
01121 }
01122
01132 function get_matchingpair_count()
01133 {
01134 return count($this->matchingpairs);
01135 }
01136
01148 function calculateReachedPoints($active_id, $pass = NULL)
01149 {
01150 global $ilDB;
01151
01152 $found_value1 = array();
01153 $found_value2 = array();
01154 if (is_null($pass))
01155 {
01156 $pass = $this->getSolutionMaxPass($active_id);
01157 }
01158 $query = sprintf("SELECT * FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
01159 $ilDB->quote($active_id . ""),
01160 $ilDB->quote($this->getId() . ""),
01161 $ilDB->quote($pass . "")
01162 );
01163 $result = $ilDB->query($query);
01164 while ($data = $result->fetchRow(DB_FETCHMODE_OBJECT))
01165 {
01166 if (strcmp($data->value1, "") != 0)
01167 {
01168 array_push($found_value1, $data->value1);
01169 array_push($found_value2, $data->value2);
01170 }
01171 }
01172 $points = 0;
01173 foreach ($found_value2 as $key => $value)
01174 {
01175 foreach ($this->matchingpairs as $answer_key => $answer_value)
01176 {
01177 if (($answer_value->getDefinitionId() == $value) and ($answer_value->getTermId() == $found_value1[$key]))
01178 {
01179 $points += $answer_value->getPoints();
01180 }
01181 }
01182 }
01183
01184 $points = parent::calculateReachedPoints($active_id, $pass = NULL, $points);
01185 return $points;
01186 }
01187
01196 function getMaximumPoints()
01197 {
01198 $points = 0;
01199 foreach ($this->matchingpairs as $key => $value)
01200 {
01201 if ($value->getPoints() > 0)
01202 {
01203 $points += $value->getPoints();
01204 }
01205 }
01206 return $points;
01207 }
01208
01219 function setImageFile($image_filename, $image_tempfilename = "")
01220 {
01221 $result = 0;
01222 if (!empty($image_tempfilename))
01223 {
01224 $image_filename = str_replace(" ", "_", $image_filename);
01225 $imagepath = $this->getImagePath();
01226 if (!file_exists($imagepath))
01227 {
01228 ilUtil::makeDirParents($imagepath);
01229 }
01230
01231 if (!ilUtil::moveUploadedFile($image_tempfilename, $image_filename, $imagepath.$image_filename))
01232 {
01233 $result = 2;
01234 }
01235 else
01236 {
01237 include_once "./content/classes/Media/class.ilObjMediaObject.php";
01238 $mimetype = ilObjMediaObject::getMimeType($imagepath . $image_filename);
01239 if (!preg_match("/^image/", $mimetype))
01240 {
01241 unlink($imagepath . $image_filename);
01242 $result = 1;
01243 }
01244 else
01245 {
01246
01247 $thumbpath = $imagepath . $image_filename . "." . "thumb.jpg";
01248 ilUtil::convertImage($imagepath.$image_filename, $thumbpath, "JPEG", 100);
01249 }
01250 }
01251 }
01252 return $result;
01253 }
01254
01264 function checkSaveData()
01265 {
01266 $result = true;
01267 $matching_values = array();
01268 foreach ($_POST as $key => $value)
01269 {
01270 if (preg_match("/^sel_matching_(\d+)/", $key, $matches))
01271 {
01272 if ((strcmp($value, "") != 0) && ($value != -1))
01273 {
01274 array_push($matching_values, $value);
01275 }
01276 }
01277 }
01278 $check_matching = array_flip($matching_values);
01279 if (count($check_matching) != count($matching_values))
01280 {
01281
01282 $result = false;
01283 sendInfo($this->lng->txt("duplicate_matching_values_selected"), TRUE);
01284 }
01285 return $result;
01286 }
01287
01298 function saveWorkingData($active_id, $pass = NULL)
01299 {
01300 global $ilDB;
01301 global $ilUser;
01302
01303 $saveWorkingDataResult = $this->checkSaveData();
01304 $entered_values = 0;
01305 if ($saveWorkingDataResult)
01306 {
01307 include_once ("./assessment/classes/class.ilObjTest.php");
01308 $activepass = ilObjTest::_getPass($active_id);
01309
01310 $query = sprintf("DELETE FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
01311 $ilDB->quote($active_id . ""),
01312 $ilDB->quote($this->getId() . ""),
01313 $ilDB->quote($activepass . "")
01314 );
01315 $result = $ilDB->query($query);
01316 foreach ($_POST as $key => $value)
01317 {
01318 if (preg_match("/^sel_matching_(\d+)/", $key, $matches))
01319 {
01320 if (!(preg_match("/initial_value_\d+/", $value)))
01321 {
01322 if ($value > -1)
01323 {
01324 $entered_values++;
01325 $query = sprintf("INSERT INTO tst_solutions (solution_id, active_fi, question_fi, value1, value2, pass, TIMESTAMP) VALUES (NULL, %s, %s, %s, %s, %s, NULL)",
01326 $ilDB->quote($active_id),
01327 $ilDB->quote($this->getId()),
01328 $ilDB->quote(trim($value)),
01329 $ilDB->quote(trim($matches[1])),
01330 $ilDB->quote($activepass . "")
01331 );
01332 $result = $ilDB->query($query);
01333 }
01334 }
01335 }
01336 }
01337 $saveWorkingDataResult = true;
01338 }
01339 if ($entered_values)
01340 {
01341 include_once ("./classes/class.ilObjAssessmentFolder.php");
01342 if (ilObjAssessmentFolder::_enabledAssessmentLogging())
01343 {
01344 $this->logAction($this->lng->txtlng("assessment", "log_user_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
01345 }
01346 }
01347 else
01348 {
01349 include_once ("./classes/class.ilObjAssessmentFolder.php");
01350 if (ilObjAssessmentFolder::_enabledAssessmentLogging())
01351 {
01352 $this->logAction($this->lng->txtlng("assessment", "log_user_not_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
01353 }
01354 }
01355 parent::saveWorkingData($active_id, $pass);
01356 return $saveWorkingDataResult;
01357 }
01358
01359 function get_random_id()
01360 {
01361 mt_srand((double)microtime()*1000000);
01362 $random_number = mt_rand(1, 100000);
01363 $found = FALSE;
01364 while ($found)
01365 {
01366 $found = FALSE;
01367 foreach ($this->matchingpairs as $key => $value)
01368 {
01369 if (($value->getTermId() == $random_number) || ($value->getDefinitionId() == $random_number))
01370 {
01371 $found = TRUE;
01372 $random_number++;
01373 }
01374 }
01375 }
01376 return $random_number;
01377 }
01378
01379 function syncWithOriginal()
01380 {
01381 global $ilDB;
01382
01383 if ($this->original_id)
01384 {
01385 $complete = 0;
01386 if ($this->isComplete())
01387 {
01388 $complete = 1;
01389 }
01390
01391 $estw_time = $this->getEstimatedWorkingTime();
01392 $estw_time = sprintf("%02d:%02d:%02d", $estw_time['h'], $estw_time['m'], $estw_time['s']);
01393
01394 $query = sprintf("UPDATE qpl_questions SET obj_fi = %s, title = %s, comment = %s, author = %s, question_text = %s, working_time=%s, points = %s, complete = %s WHERE question_id = %s",
01395 $ilDB->quote($this->obj_id. ""),
01396 $ilDB->quote($this->title. ""),
01397 $ilDB->quote($this->comment. ""),
01398 $ilDB->quote($this->author. ""),
01399 $ilDB->quote($this->question. ""),
01400 $ilDB->quote($estw_time. ""),
01401 $ilDB->quote($this->getMaximumPoints() . ""),
01402 $ilDB->quote($complete. ""),
01403 $ilDB->quote($this->original_id. "")
01404 );
01405 $result = $ilDB->query($query);
01406 $query = sprintf("UPDATE qpl_question_matching SET shuffle = %, matching_type = %s WHERE question_fi = %s",
01407 $ilDB->quote($this->shuffle . ""),
01408 $ilDB->quote($this->matching_type. ""),
01409 $ilDB->quote($this->original_id . "")
01410 );
01411 $result = $ilDB->query($query);
01412
01413 if ($result == DB_OK)
01414 {
01415
01416
01417 $query = sprintf("DELETE FROM qpl_answer_matching WHERE question_fi = %s",
01418 $ilDB->quote($this->original_id)
01419 );
01420 $result = $ilDB->query($query);
01421
01422 foreach ($this->matchingpairs as $key => $value)
01423 {
01424 $matching_obj = $this->matchingpairs[$key];
01425 $query = sprintf("INSERT INTO qpl_answer_matching (answer_id, question_fi, answertext, points, aorder, matchingtext, matching_order) VALUES (NULL, %s, %s, %s, %s, %s, %s)",
01426 $ilDB->quote($this->original_id . ""),
01427 $ilDB->quote($matching_obj->getTerm() . ""),
01428 $ilDB->quote($matching_obj->getPoints() . ""),
01429 $ilDB->quote($matching_obj->getTermId() . ""),
01430 $ilDB->quote($matching_obj->getDefinition() . ""),
01431 $ilDB->quote($matching_obj->getDefinitionId() . "")
01432 );
01433 $matching_result = $ilDB->query($query);
01434 }
01435 }
01436 parent::syncWithOriginal();
01437 }
01438 }
01439
01440 function pc_array_shuffle($array) {
01441 $i = count($array);
01442 mt_srand((double)microtime()*1000000);
01443 while(--$i)
01444 {
01445 $j = mt_rand(0, $i);
01446 if ($i != $j)
01447 {
01448
01449 $tmp = $array[$j];
01450 $array[$j] = $array[$i];
01451 $array[$i] = $tmp;
01452 }
01453 }
01454 return $array;
01455 }
01456
01465 function getQuestionType()
01466 {
01467 return 4;
01468 }
01469
01478 function getAdditionalTableName()
01479 {
01480 return "qpl_question_matching";
01481 }
01482
01491 function getAnswerTableName()
01492 {
01493 return "qpl_answer_matching";
01494 }
01495 }
01496
01497 ?>