ILIAS  eassessment Revision 61809
 All Data Structures Namespaces Files Functions Variables Groups Pages
class.assTextSubset.php
Go to the documentation of this file.
1 <?php
2  /*
3  +----------------------------------------------------------------------------+
4  | ILIAS open source |
5  +----------------------------------------------------------------------------+
6  | Copyright (c) 1998-2001 ILIAS open source, University of Cologne |
7  | |
8  | This program is free software; you can redistribute it and/or |
9  | modify it under the terms of the GNU General Public License |
10  | as published by the Free Software Foundation; either version 2 |
11  | of the License, or (at your option) any later version. |
12  | |
13  | This program is distributed in the hope that it will be useful, |
14  | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16  | GNU General Public License for more details. |
17  | |
18  | You should have received a copy of the GNU General Public License |
19  | along with this program; if not, write to the Free Software |
20  | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
21  +----------------------------------------------------------------------------+
22 */
23 include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
24 include_once "./Modules/Test/classes/inc.AssessmentConstants.php";
25 
37 class assTextSubset extends assQuestion
38 {
46  var $answers;
47 
55  var $correctanswers;
56 
63 
71  var $text_rating;
72 
86  function __construct(
87  $title = "",
88  $comment = "",
89  $author = "",
90  $owner = -1,
91  $question = ""
92  )
93  {
95  $this->answers = array();
96  $this->correctanswers = 0;
97  }
98 
105  function isComplete()
106  {
107  if (($this->title) and ($this->author) and ($this->question) and (count($this->answers) >= $this->correctanswers) and ($this->getMaximumPoints() > 0))
108  {
109  return true;
110  }
111  else
112  {
113  return false;
114  }
115  }
116 
123  function saveToDb($original_id = "")
124  {
125  global $ilDB;
126 
128 
129  // save additional data
130  $affectedRows = $ilDB->manipulateF("DELETE FROM " . $this->getAdditionalTableName() . " WHERE question_fi = %s",
131  array("integer"),
132  array($this->getId())
133  );
134 
135  $affectedRows = $ilDB->manipulateF("INSERT INTO " . $this->getAdditionalTableName() . " (question_fi, textgap_rating, correctanswers, answerscount) VALUES (%s, %s, %s, %s)",
136  array("integer", "text", "integer", "integer"),
137  array(
138  $this->getId(),
139  $this->getTextRating(),
140  $this->getCorrectAnswers(),
141  $this->getAllAnswers()
142  )
143  );
144 
145  $affectedRows = $ilDB->manipulateF("DELETE FROM qpl_a_textsubset WHERE question_fi = %s",
146  array('integer'),
147  array($this->getId())
148  );
149 
150  foreach ($this->answers as $key => $value)
151  {
152  $answer_obj = $this->answers[$key];
153  $next_id = $ilDB->nextId('qpl_a_textsubset');
154  $query = $ilDB->manipulateF("INSERT INTO qpl_a_textsubset (answer_id, question_fi, answertext, points, aorder, tstamp) VALUES (%s, %s, %s, %s, %s, %s)",
155  array('integer', 'integer', 'text', 'float', 'integer', 'integer'),
156  array(
157  $next_id,
158  $this->getId(),
159  $answer_obj->getAnswertext(),
160  $answer_obj->getPoints(),
161  $answer_obj->getOrder(),
162  time()
163  )
164  );
165  }
166 
168  }
169 
177  function loadFromDb($question_id)
178  {
179  global $ilDB;
180 
181  $result = $ilDB->queryF("SELECT qpl_questions.*, " . $this->getAdditionalTableName() . ".* FROM qpl_questions LEFT JOIN " . $this->getAdditionalTableName() . " ON " . $this->getAdditionalTableName() . ".question_fi = qpl_questions.question_id WHERE qpl_questions.question_id = %s",
182  array("integer"),
183  array($question_id)
184  );
185  if ($result->numRows() == 1)
186  {
187  $data = $ilDB->fetchAssoc($result);
188  $this->setId($question_id);
189  $this->setObjId($data["obj_fi"]);
190  $this->setNrOfTries($data['nr_of_tries']);
191  $this->setTitle($data["title"]);
192  $this->setComment($data["description"]);
193  $this->setOriginalId($data["original_id"]);
194  $this->setAuthor($data["author"]);
195  $this->setPoints($data["points"]);
196  $this->setOwner($data["owner"]);
197  include_once("./Services/RTE/classes/class.ilRTE.php");
198  $this->setQuestion(ilRTE::_replaceMediaObjectImageSrc($data["question_text"], 1));
199  $this->setCorrectAnswers($data["correctanswers"]);
200  $this->setAllAnswers($data["answerscount"]);
201  $this->setTextRating($data["textgap_rating"]);
202  $this->setEstimatedWorkingTime(substr($data["working_time"], 0, 2), substr($data["working_time"], 3, 2), substr($data["working_time"], 6, 2));
203  }
204 
205 
206  $result = $ilDB->queryF("SELECT * FROM qpl_a_textsubset WHERE question_fi = %s ORDER BY aorder ASC",
207  array('integer'),
208  array($question_id)
209  );
210  include_once "./Modules/TestQuestionPool/classes/class.assAnswerBinaryStateImage.php";
211  if ($result->numRows() > 0)
212  {
213  while ($data = $ilDB->fetchAssoc($result))
214  {
215  array_push($this->answers, new ASS_AnswerBinaryStateImage($data["answertext"], $data["points"], $data["aorder"]));
216  }
217  }
218 
219  parent::loadFromDb($question_id);
220  }
221 
227  function addAnswer($answertext, $points, $order)
228  {
229  include_once "./Modules/TestQuestionPool/classes/class.assAnswerBinaryStateImage.php";
230  if (array_key_exists($order, $this->answers))
231  {
232  // insert answer
233  $answer = new ASS_AnswerBinaryStateImage($answertext, $points, $order);
234  $newchoices = array();
235  for ($i = 0; $i < $order; $i++)
236  {
237  array_push($newchoices, $this->answers[$i]);
238  }
239  array_push($newchoices, $answer);
240  for ($i = $order; $i < count($this->answers); $i++)
241  {
242  $changed = $this->answers[$i];
243  $changed->setOrder($i+1);
244  array_push($newchoices, $changed);
245  }
246  $this->answers = $newchoices;
247  }
248  else
249  {
250  // add answer
251  array_push($this->answers, new ASS_AnswerBinaryStateImage($answertext, $points, count($this->answers)));
252  }
253  }
254 
260  function duplicate($for_test = true, $title = "", $author = "", $owner = "")
261  {
262  if ($this->id <= 0)
263  {
264  // The question has not been saved. It cannot be duplicated
265  return;
266  }
267  // duplicate the question in database
268  $this_id = $this->getId();
269  $clone = $this;
270  include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
272  $clone->id = -1;
273  if ($title)
274  {
275  $clone->setTitle($title);
276  }
277 
278  if ($author)
279  {
280  $clone->setAuthor($author);
281  }
282  if ($owner)
283  {
284  $clone->setOwner($owner);
285  }
286 
287  if ($for_test)
288  {
289  $clone->saveToDb($original_id);
290  }
291  else
292  {
293  $clone->saveToDb();
294  }
295 
296  // copy question page content
297  $clone->copyPageOfQuestion($this_id);
298  // copy XHTML media objects
299  $clone->copyXHTMLMediaObjectsOfQuestion($this_id);
300  // duplicate the generic feedback
301  $clone->duplicateFeedbackGeneric($this_id);
302  $clone->onDuplicate($this_id);
303 
304  return $clone->id;
305  }
306 
312  function copyObject($target_questionpool, $title = "")
313  {
314  if ($this->id <= 0)
315  {
316  // The question has not been saved. It cannot be duplicated
317  return;
318  }
319  // duplicate the question in database
320  $clone = $this;
321  include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
323  $clone->id = -1;
324  $source_questionpool = $this->getObjId();
325  $clone->setObjId($target_questionpool);
326  if ($title)
327  {
328  $clone->setTitle($title);
329  }
330  $clone->saveToDb();
331 
332  // copy question page content
333  $clone->copyPageOfQuestion($original_id);
334  // copy XHTML media objects
335  $clone->copyXHTMLMediaObjectsOfQuestion($original_id);
336  // duplicate the generic feedback
337  $clone->duplicateFeedbackGeneric($original_id);
338  $clone->onCopy($this->getObjId(), $this->getId());
339 
340  return $clone->id;
341  }
342 
350  function getAnswerCount()
351  {
352  return count($this->answers);
353  }
354 
364  function getAnswer($index = 0)
365  {
366  if ($index < 0) return NULL;
367  if (count($this->answers) < 1) return NULL;
368  if ($index >= count($this->answers)) return NULL;
369 
370  return $this->answers[$index];
371  }
372 
381  function deleteAnswer($index = 0)
382  {
383  if ($index < 0) return;
384  if (count($this->answers) < 1) return;
385  if ($index >= count($this->answers)) return;
386  unset($this->answers[$index]);
387  $this->answers = array_values($this->answers);
388  for ($i = 0; $i < count($this->answers); $i++)
389  {
390  if ($this->answers[$i]->getOrder() > $index)
391  {
392  $this->answers[$i]->setOrder($i);
393  }
394  }
395  }
396 
403  function flushAnswers()
404  {
405  $this->answers = array();
406  }
407 
414  function getMaximumPoints()
415  {
416  $points = array();
417  foreach ($this->answers as $answer)
418  {
419  if ($answer->getPoints() > 0)
420  {
421  array_push($points, $answer->getPoints());
422  }
423  }
424  rsort($points, SORT_NUMERIC);
425  $maxpoints = 0;
426  for ($counter = 0; $counter < $this->getCorrectAnswers(); $counter++)
427  {
428  $maxpoints += $points[$counter];
429  }
430  return $maxpoints;
431  }
432 
440  {
441  $available_answers = array();
442  foreach ($this->answers as $answer)
443  {
444  array_push($available_answers, $answer->getAnswertext());
445  }
446  return $available_answers;
447  }
448 
459  function isAnswerCorrect($answers, $answer)
460  {
461  include_once "./Services/Utilities/classes/class.ilStr.php";
462  $result = 0;
463  $textrating = $this->getTextRating();
464  foreach ($answers as $key => $value)
465  {
466  switch ($textrating)
467  {
469  if (strcmp(ilStr::strToLower($value), ilStr::strToLower($answer)) == 0) return $key;
470  break;
472  if (strcmp($value, $answer) == 0) return $key;
473  break;
475  if (levenshtein($value, $answer) <= 1) return $key;
476  break;
478  if (levenshtein($value, $answer) <= 2) return $key;
479  break;
481  if (levenshtein($value, $answer) <= 3) return $key;
482  break;
484  if (levenshtein($value, $answer) <= 4) return $key;
485  break;
487  if (levenshtein($value, $answer) <= 5) return $key;
488  break;
489  }
490  }
491  return FALSE;
492  }
493 
501  function getTextRating()
502  {
503  return $this->text_rating;
504  }
505 
513  function setTextRating($a_text_rating)
514  {
515  switch ($a_text_rating)
516  {
524  $this->text_rating = $a_text_rating;
525  break;
526  default:
527  $this->text_rating = TEXTGAP_RATING_CASEINSENSITIVE;
528  break;
529  }
530  }
531 
541  function calculateReachedPoints($active_id, $pass = NULL)
542  {
543  global $ilDB;
544 
545  $available_answers =& $this->getAvailableAnswers();
546  $found_counter = 0;
547 
548  if (is_null($pass))
549  {
550  $pass = $this->getSolutionMaxPass($active_id);
551  }
552  $result = $ilDB->queryF("SELECT * FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
553  array('integer','integer','integer'),
554  array($active_id, $this->getId(), $pass)
555  );
556  while ($data = $ilDB->fetchAssoc($result))
557  {
558  $enteredtext = $data["value1"];
559  $index = $this->isAnswerCorrect($available_answers, $enteredtext);
560  if ($index !== FALSE)
561  {
562  unset($available_answers[$index]);
563  $points += $this->answers[$index]->getPoints();
564  }
565  }
566 
567  $points = parent::calculateReachedPoints($active_id, $pass = NULL, $points);
568  return $points;
569  }
570 
577  function setCorrectAnswers($a_correct_answers)
578  {
579  $this->correctanswers = $a_correct_answers;
580  }
581 
588  function setAllAnswers($a_all_answers)
589  {
590  $this->allanswers = $a_all_answers;
591  }
592 
599  function getCorrectAnswers()
600  {
601  return $this->correctanswers;
602  }
603 
610  function getAllAnswers()
611  {
612  return $this->allanswers;
613  }
614 
623  function saveWorkingData($active_id, $pass = NULL)
624  {
625  global $ilDB;
626  global $ilUser;
627 
628  if (is_null($pass))
629  {
630  include_once "./Modules/Test/classes/class.ilObjTest.php";
631  $pass = ilObjTest::_getPass($active_id);
632  }
633  $entered_values = 0;
634 
635  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
636  array('integer','integer','integer'),
637  array($active_id, $this->getId(), $pass)
638  );
639  foreach ($_POST as $key => $value)
640  {
641  if (preg_match("/^TEXTSUBSET_(\d+)/", $key, $matches))
642  {
643  if (strlen($value))
644  {
645  $next_id = $ilDB->nextId('tst_solutions');
646  $affectedRows = $ilDB->insert("tst_solutions", array(
647  "solution_id" => array("integer", $next_id),
648  "active_fi" => array("integer", $active_id),
649  "question_fi" => array("integer", $this->getId()),
650  "value1" => array("clob", trim($value)),
651  "value2" => array("clob", null),
652  "pass" => array("integer", $pass),
653  "tstamp" => array("integer", time())
654  ));
655  $entered_values++;
656  }
657  }
658  }
659  if ($entered_values)
660  {
661  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
663  {
664  $this->logAction($this->lng->txtlng("assessment", "log_user_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
665  }
666  }
667  else
668  {
669  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
671  {
672  $this->logAction($this->lng->txtlng("assessment", "log_user_not_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
673  }
674  }
675  parent::saveWorkingData($active_id, $pass);
676  return true;
677  }
678 
685  function getQuestionType()
686  {
687  return "assTextSubset";
688  }
689 
696  function &joinAnswers()
697  {
698  $join = array();
699  foreach ($this->answers as $answer)
700  {
701  if (!is_array($join[$answer->getPoints() . ""]))
702  {
703  $join[$answer->getPoints() . ""] = array();
704  }
705  array_push($join[$answer->getPoints() . ""], $answer->getAnswertext());
706  }
707  return $join;
708  }
709 
717  {
718  $maxwidth = 0;
719  foreach ($this->answers as $answer)
720  {
721  $len = strlen($answer->getAnswertext());
722  if ($len > $maxwidth) $maxwidth = $len;
723  }
724  return $maxwidth + 3;
725  }
726 
734  {
735  return "qpl_qst_textsubset";
736  }
737 
745  {
746  return "qpl_a_textsubset";
747  }
748 
754  {
756  }
757 
767  public function setExportDetailsXLS(&$adapter, $startrow, $active_id, $pass)
768  {
769  $solutions = $this->getSolutionValues($active_id, $pass);
770  $adapter->setCellValue($startrow, 0, $this->lng->txt($this->getQuestionType()), CELL_FORMAT_TITLE);
771  $adapter->setCellValue($startrow, 1, $this->getTitle(), CELL_FORMAT_TITLE);
772  $i = 1;
773  foreach ($solutions as $solution)
774  {
775  $adapter->setCellValue($startrow + $i, 0, $solution["value1"]);
776  $i++;
777  }
778  return $startrow + $i + 1;
779  }
780 
781  public function getAnswers()
782  {
783  return $this->answers;
784  }
785 }
786 
787 ?>