• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

Modules/TestQuestionPool/classes/class.assClozeTest.php

Go to the documentation of this file.
00001 <?php
00002  /*
00003    +----------------------------------------------------------------------------+
00004    | ILIAS open source                                                          |
00005    +----------------------------------------------------------------------------+
00006    | Copyright (c) 1998-2001 ILIAS open source, University of Cologne           |
00007    |                                                                            |
00008    | This program is free software; you can redistribute it and/or              |
00009    | modify it under the terms of the GNU General Public License                |
00010    | as published by the Free Software Foundation; either version 2             |
00011    | of the License, or (at your option) any later version.                     |
00012    |                                                                            |
00013    | This program is distributed in the hope that it will be useful,            |
00014    | but WITHOUT ANY WARRANTY; without even the implied warranty of             |
00015    | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              |
00016    | GNU General Public License for more details.                               |
00017    |                                                                            |
00018    | You should have received a copy of the GNU General Public License          |
00019    | along with this program; if not, write to the Free Software                |
00020    | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
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                                 // replacement of old syntax with new syntax
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                         // open the cloze gaps with all answers
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                 // cleanup RTE images which are not inserted into the question text
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                                 // create page object of question
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                         // delete old answers
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                                 // create text gaps by default
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                                 // only allow notation with "." for real numbers
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                         // The question has not been saved. It cannot be duplicated
00835                         return;
00836                 }
00837                 // duplicate the question in database
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                 // copy question page content
00865                 $clone->copyPageOfQuestion($this_id);
00866                 // copy XHTML media objects
00867                 $clone->copyXHTMLMediaObjectsOfQuestion($this_id);
00868                 // duplicate the generic feedback
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                         // The question has not been saved. It cannot be duplicated
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                 // copy question page content
00901                 $clone->copyPageOfQuestion($original_id);
00902                 // copy XHTML media objects
00903                 $clone->copyXHTMLMediaObjectsOfQuestion($original_id);
00904                 // duplicate the generic feedback
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                                 // this is the last answer text => remove the gap
00951                                 $this->deleteGap($gap_index);
00952                         }
00953                         else
00954                         {
00955                                 // remove the answer text
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(); // for identical scoring checks
01121                 $solution_values_select = array(); // for identical scoring checks
01122                 $solution_values_numeric = array(); // for identical scoring checks
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                                                         // check if the same solution text was already entered
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                                                         // check if the same solution value was already entered
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                                                                                 // check if the same solution value was already entered
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 //TODO point of changes
01469 }
01470 ?>

Generated on Fri Dec 13 2013 17:56:53 for ILIAS Release_3_9_x_branch .rev 46835 by  doxygen 1.7.1