ILIAS  Release_4_0_x_branch Revision 61816
 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 
38 {
46  var $answers;
47 
56 
65 
79  function __construct(
80  $title = "",
81  $comment = "",
82  $author = "",
83  $owner = -1,
84  $question = ""
85  )
86  {
88  $this->answers = array();
89  $this->correctanswers = 0;
90  }
91 
98  function isComplete()
99  {
100  if (($this->title) and ($this->author) and ($this->question) and (count($this->answers) >= $this->correctanswers) and ($this->getMaximumPoints() > 0))
101  {
102  return true;
103  }
104  else
105  {
106  return false;
107  }
108  }
109 
116  function saveToDb($original_id = "")
117  {
118  global $ilDB;
119 
121 
122  // save additional data
123  $affectedRows = $ilDB->manipulateF("DELETE FROM " . $this->getAdditionalTableName() . " WHERE question_fi = %s",
124  array("integer"),
125  array($this->getId())
126  );
127 
128  $affectedRows = $ilDB->manipulateF("INSERT INTO " . $this->getAdditionalTableName() . " (question_fi, textgap_rating, correctanswers) VALUES (%s, %s, %s)",
129  array("integer", "text", "integer"),
130  array(
131  $this->getId(),
132  $this->getTextRating(),
133  $this->getCorrectAnswers()
134  )
135  );
136 
137  $affectedRows = $ilDB->manipulateF("DELETE FROM qpl_a_textsubset WHERE question_fi = %s",
138  array('integer'),
139  array($this->getId())
140  );
141 
142  foreach ($this->answers as $key => $value)
143  {
144  $answer_obj = $this->answers[$key];
145  $next_id = $ilDB->nextId('qpl_a_textsubset');
146  $query = $ilDB->manipulateF("INSERT INTO qpl_a_textsubset (answer_id, question_fi, answertext, points, aorder, tstamp) VALUES (%s, %s, %s, %s, %s, %s)",
147  array('integer', 'integer', 'text', 'float', 'integer', 'integer'),
148  array(
149  $next_id,
150  $this->getId(),
151  $answer_obj->getAnswertext(),
152  $answer_obj->getPoints(),
153  $answer_obj->getOrder(),
154  time()
155  )
156  );
157  }
158 
160  }
161 
169  function loadFromDb($question_id)
170  {
171  global $ilDB;
172 
173  $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",
174  array("integer"),
175  array($question_id)
176  );
177  if ($result->numRows() == 1)
178  {
179  $data = $ilDB->fetchAssoc($result);
180  $this->setId($question_id);
181  $this->setObjId($data["obj_fi"]);
182  $this->setNrOfTries($data['nr_of_tries']);
183  $this->setTitle($data["title"]);
184  $this->setComment($data["description"]);
185  $this->setOriginalId($data["original_id"]);
186  $this->setAuthor($data["author"]);
187  $this->setPoints($data["points"]);
188  $this->setOwner($data["owner"]);
189  include_once("./Services/RTE/classes/class.ilRTE.php");
190  $this->setQuestion(ilRTE::_replaceMediaObjectImageSrc($data["question_text"], 1));
191  $this->setCorrectAnswers($data["correctanswers"]);
192  $this->setTextRating($data["textgap_rating"]);
193  $this->setEstimatedWorkingTime(substr($data["working_time"], 0, 2), substr($data["working_time"], 3, 2), substr($data["working_time"], 6, 2));
194  }
195 
196 
197  $result = $ilDB->queryF("SELECT * FROM qpl_a_textsubset WHERE question_fi = %s ORDER BY aorder ASC",
198  array('integer'),
199  array($question_id)
200  );
201  include_once "./Modules/TestQuestionPool/classes/class.assAnswerBinaryStateImage.php";
202  if ($result->numRows() > 0)
203  {
204  while ($data = $ilDB->fetchAssoc($result))
205  {
206  array_push($this->answers, new ASS_AnswerBinaryStateImage($data["answertext"], $data["points"], $data["aorder"]));
207  }
208  }
209 
210  parent::loadFromDb($question_id);
211  }
212 
218  function addAnswer($answertext, $points, $order)
219  {
220  include_once "./Modules/TestQuestionPool/classes/class.assAnswerBinaryStateImage.php";
221  if (array_key_exists($order, $this->answers))
222  {
223  // insert answer
224  $answer = new ASS_AnswerBinaryStateImage($answertext, $points, $order);
225  $newchoices = array();
226  for ($i = 0; $i < $order; $i++)
227  {
228  array_push($newchoices, $this->answers[$i]);
229  }
230  array_push($newchoices, $answer);
231  for ($i = $order; $i < count($this->answers); $i++)
232  {
233  $changed = $this->answers[$i];
234  $changed->setOrder($i+1);
235  array_push($newchoices, $changed);
236  }
237  $this->answers = $newchoices;
238  }
239  else
240  {
241  // add answer
242  array_push($this->answers, new ASS_AnswerBinaryStateImage($answertext, $points, count($this->answers)));
243  }
244  }
245 
251  function duplicate($for_test = true, $title = "", $author = "", $owner = "")
252  {
253  if ($this->id <= 0)
254  {
255  // The question has not been saved. It cannot be duplicated
256  return;
257  }
258  // duplicate the question in database
259  $this_id = $this->getId();
260  $clone = $this;
261  include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
263  $clone->id = -1;
264  if ($title)
265  {
266  $clone->setTitle($title);
267  }
268 
269  if ($author)
270  {
271  $clone->setAuthor($author);
272  }
273  if ($owner)
274  {
275  $clone->setOwner($owner);
276  }
277 
278  if ($for_test)
279  {
280  $clone->saveToDb($original_id);
281  }
282  else
283  {
284  $clone->saveToDb();
285  }
286 
287  // copy question page content
288  $clone->copyPageOfQuestion($this_id);
289  // copy XHTML media objects
290  $clone->copyXHTMLMediaObjectsOfQuestion($this_id);
291  // duplicate the generic feedback
292  $clone->duplicateFeedbackGeneric($this_id);
293  $clone->onDuplicate($this_id);
294 
295  return $clone->id;
296  }
297 
303  function copyObject($target_questionpool, $title = "")
304  {
305  if ($this->id <= 0)
306  {
307  // The question has not been saved. It cannot be duplicated
308  return;
309  }
310  // duplicate the question in database
311  $clone = $this;
312  include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
314  $clone->id = -1;
315  $source_questionpool = $this->getObjId();
316  $clone->setObjId($target_questionpool);
317  if ($title)
318  {
319  $clone->setTitle($title);
320  }
321  $clone->saveToDb();
322 
323  // copy question page content
324  $clone->copyPageOfQuestion($original_id);
325  // copy XHTML media objects
326  $clone->copyXHTMLMediaObjectsOfQuestion($original_id);
327  // duplicate the generic feedback
328  $clone->duplicateFeedbackGeneric($original_id);
329  $clone->onCopy($this->getObjId(), $this->getId());
330 
331  return $clone->id;
332  }
333 
341  function getAnswerCount()
342  {
343  return count($this->answers);
344  }
345 
355  function getAnswer($index = 0)
356  {
357  if ($index < 0) return NULL;
358  if (count($this->answers) < 1) return NULL;
359  if ($index >= count($this->answers)) return NULL;
360 
361  return $this->answers[$index];
362  }
363 
372  function deleteAnswer($index = 0)
373  {
374  if ($index < 0) return;
375  if (count($this->answers) < 1) return;
376  if ($index >= count($this->answers)) return;
377  unset($this->answers[$index]);
378  $this->answers = array_values($this->answers);
379  for ($i = 0; $i < count($this->answers); $i++)
380  {
381  if ($this->answers[$i]->getOrder() > $index)
382  {
383  $this->answers[$i]->setOrder($i);
384  }
385  }
386  }
387 
394  function flushAnswers()
395  {
396  $this->answers = array();
397  }
398 
405  function getMaximumPoints()
406  {
407  $points = array();
408  foreach ($this->answers as $answer)
409  {
410  if ($answer->getPoints() > 0)
411  {
412  array_push($points, $answer->getPoints());
413  }
414  }
415  rsort($points, SORT_NUMERIC);
416  $maxpoints = 0;
417  for ($counter = 0; $counter < $this->getCorrectAnswers(); $counter++)
418  {
419  $maxpoints += $points[$counter];
420  }
421  return $maxpoints;
422  }
423 
431  {
432  $available_answers = array();
433  foreach ($this->answers as $answer)
434  {
435  array_push($available_answers, $answer->getAnswertext());
436  }
437  return $available_answers;
438  }
439 
450  function isAnswerCorrect($answers, $answer)
451  {
452  include_once "./Services/Utilities/classes/class.ilStr.php";
453  $result = 0;
454  $textrating = $this->getTextRating();
455  foreach ($answers as $key => $value)
456  {
457  switch ($textrating)
458  {
460  if (strcmp(ilStr::strToLower($value), ilStr::strToLower($answer)) == 0) return $key;
461  break;
463  if (strcmp($value, $answer) == 0) return $key;
464  break;
466  if (levenshtein($value, $answer) <= 1) return $key;
467  break;
469  if (levenshtein($value, $answer) <= 2) return $key;
470  break;
472  if (levenshtein($value, $answer) <= 3) return $key;
473  break;
475  if (levenshtein($value, $answer) <= 4) return $key;
476  break;
478  if (levenshtein($value, $answer) <= 5) return $key;
479  break;
480  }
481  }
482  return FALSE;
483  }
484 
492  function getTextRating()
493  {
494  return $this->text_rating;
495  }
496 
504  function setTextRating($a_text_rating)
505  {
506  switch ($a_text_rating)
507  {
515  $this->text_rating = $a_text_rating;
516  break;
517  default:
518  $this->text_rating = TEXTGAP_RATING_CASEINSENSITIVE;
519  break;
520  }
521  }
522 
532  function calculateReachedPoints($active_id, $pass = NULL)
533  {
534  global $ilDB;
535 
536  $available_answers =& $this->getAvailableAnswers();
537  $found_counter = 0;
538 
539  if (is_null($pass))
540  {
541  $pass = $this->getSolutionMaxPass($active_id);
542  }
543  $result = $ilDB->queryF("SELECT * FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
544  array('integer','integer','integer'),
545  array($active_id, $this->getId(), $pass)
546  );
547  while ($data = $ilDB->fetchAssoc($result))
548  {
549  $enteredtext = $data["value1"];
550  $index = $this->isAnswerCorrect($available_answers, $enteredtext);
551  if ($index !== FALSE)
552  {
553  unset($available_answers[$index]);
554  $points += $this->answers[$index]->getPoints();
555  }
556  }
557 
558  $points = parent::calculateReachedPoints($active_id, $pass = NULL, $points);
559  return $points;
560  }
561 
568  function setCorrectAnswers($a_correct_answers)
569  {
570  $this->correctanswers = $a_correct_answers;
571  }
572 
579  function getCorrectAnswers()
580  {
581  return $this->correctanswers;
582  }
583 
592  function saveWorkingData($active_id, $pass = NULL)
593  {
594  global $ilDB;
595  global $ilUser;
596 
597  if (is_null($pass))
598  {
599  include_once "./Modules/Test/classes/class.ilObjTest.php";
600  $pass = ilObjTest::_getPass($active_id);
601  }
602  $entered_values = 0;
603 
604  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
605  array('integer','integer','integer'),
606  array($active_id, $this->getId(), $pass)
607  );
608  foreach ($_POST as $key => $value)
609  {
610  if (preg_match("/^TEXTSUBSET_(\d+)/", $key, $matches))
611  {
612  if (strlen($value))
613  {
614  $next_id = $ilDB->nextId('tst_solutions');
615  $affectedRows = $ilDB->insert("tst_solutions", array(
616  "solution_id" => array("integer", $next_id),
617  "active_fi" => array("integer", $active_id),
618  "question_fi" => array("integer", $this->getId()),
619  "value1" => array("clob", trim($value)),
620  "value2" => array("clob", null),
621  "pass" => array("integer", $pass),
622  "tstamp" => array("integer", time())
623  ));
624  $entered_values++;
625  }
626  }
627  }
628  if ($entered_values)
629  {
630  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
632  {
633  $this->logAction($this->lng->txtlng("assessment", "log_user_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
634  }
635  }
636  else
637  {
638  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
640  {
641  $this->logAction($this->lng->txtlng("assessment", "log_user_not_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
642  }
643  }
644  parent::saveWorkingData($active_id, $pass);
645  return true;
646  }
647 
654  function getQuestionType()
655  {
656  return "assTextSubset";
657  }
658 
665  function &joinAnswers()
666  {
667  $join = array();
668  foreach ($this->answers as $answer)
669  {
670  if (!is_array($join[$answer->getPoints() . ""]))
671  {
672  $join[$answer->getPoints() . ""] = array();
673  }
674  array_push($join[$answer->getPoints() . ""], $answer->getAnswertext());
675  }
676  return $join;
677  }
678 
686  {
687  $maxwidth = 0;
688  foreach ($this->answers as $answer)
689  {
690  $len = strlen($answer->getAnswertext());
691  if ($len > $maxwidth) $maxwidth = $len;
692  }
693  return $maxwidth + 3;
694  }
695 
703  {
704  return "qpl_qst_textsubset";
705  }
706 
714  {
715  return "qpl_a_textsubset";
716  }
717 
723  {
725  }
726 
739  public function setExportDetailsXLS(&$worksheet, $startrow, $active_id, $pass, &$format_title, &$format_bold)
740  {
741  include_once ("./Services/Excel/classes/class.ilExcelUtils.php");
742  $solutions = $this->getSolutionValues($active_id, $pass);
743  $worksheet->writeString($startrow, 0, ilExcelUtils::_convert_text($this->lng->txt($this->getQuestionType())), $format_title);
744  $worksheet->writeString($startrow, 1, ilExcelUtils::_convert_text($this->getTitle()), $format_title);
745  $i = 1;
746  foreach ($solutions as $solution)
747  {
748  $worksheet->write($startrow + $i, 0, ilExcelUtils::_convert_text($solution["value1"]));
749  $i++;
750  }
751  return $startrow + $i + 1;
752  }
753 
754  public function getAnswers()
755  {
756  return $this->answers;
757  }
758 }
759 
760 ?>