ILIAS  Release_4_2_x_branch Revision 61807
 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 (strlen($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 = "", $testObjId = null)
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 
261  if( (int)$testObjId > 0 )
262  {
263  $thisObjId = $this->getObjId();
264  }
265 
266  $clone = $this;
267  include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
269  $clone->id = -1;
270 
271  if( (int)$testObjId > 0 )
272  {
273  $clone->setObjId($testObjId);
274  }
275 
276  if ($title)
277  {
278  $clone->setTitle($title);
279  }
280 
281  if ($author)
282  {
283  $clone->setAuthor($author);
284  }
285  if ($owner)
286  {
287  $clone->setOwner($owner);
288  }
289 
290  if ($for_test)
291  {
292  $clone->saveToDb($original_id);
293  }
294  else
295  {
296  $clone->saveToDb();
297  }
298 
299  // copy question page content
300  $clone->copyPageOfQuestion($this_id);
301  // copy XHTML media objects
302  $clone->copyXHTMLMediaObjectsOfQuestion($this_id);
303  // duplicate the generic feedback
304  $clone->duplicateFeedbackGeneric($this_id);
305 
306  $clone->onDuplicate($thisObjId, $this_id, $clone->getObjId(), $clone->getId());
307 
308  return $clone->id;
309  }
310 
316  function copyObject($target_questionpool, $title = "")
317  {
318  if ($this->id <= 0)
319  {
320  // The question has not been saved. It cannot be duplicated
321  return;
322  }
323  // duplicate the question in database
324  $clone = $this;
325  include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
327  $clone->id = -1;
328  $source_questionpool = $this->getObjId();
329  $clone->setObjId($target_questionpool);
330  if ($title)
331  {
332  $clone->setTitle($title);
333  }
334  $clone->saveToDb();
335 
336  // copy question page content
337  $clone->copyPageOfQuestion($original_id);
338  // copy XHTML media objects
339  $clone->copyXHTMLMediaObjectsOfQuestion($original_id);
340  // duplicate the generic feedback
341  $clone->duplicateFeedbackGeneric($original_id);
342  $clone->onCopy($this->getObjId(), $this->getId());
343 
344  return $clone->id;
345  }
346 
354  function getAnswerCount()
355  {
356  return count($this->answers);
357  }
358 
368  function getAnswer($index = 0)
369  {
370  if ($index < 0) return NULL;
371  if (count($this->answers) < 1) return NULL;
372  if ($index >= count($this->answers)) return NULL;
373 
374  return $this->answers[$index];
375  }
376 
385  function deleteAnswer($index = 0)
386  {
387  if ($index < 0) return;
388  if (count($this->answers) < 1) return;
389  if ($index >= count($this->answers)) return;
390  unset($this->answers[$index]);
391  $this->answers = array_values($this->answers);
392  for ($i = 0; $i < count($this->answers); $i++)
393  {
394  if ($this->answers[$i]->getOrder() > $index)
395  {
396  $this->answers[$i]->setOrder($i);
397  }
398  }
399  }
400 
407  function flushAnswers()
408  {
409  $this->answers = array();
410  }
411 
418  function getMaximumPoints()
419  {
420  $points = array();
421  foreach ($this->answers as $answer)
422  {
423  if ($answer->getPoints() > 0)
424  {
425  array_push($points, $answer->getPoints());
426  }
427  }
428  rsort($points, SORT_NUMERIC);
429  $maxpoints = 0;
430  for ($counter = 0; $counter < $this->getCorrectAnswers(); $counter++)
431  {
432  $maxpoints += $points[$counter];
433  }
434  return $maxpoints;
435  }
436 
444  {
445  $available_answers = array();
446  foreach ($this->answers as $answer)
447  {
448  array_push($available_answers, $answer->getAnswertext());
449  }
450  return $available_answers;
451  }
452 
463  function isAnswerCorrect($answers, $answer)
464  {
465  include_once "./Services/Utilities/classes/class.ilStr.php";
466  $result = 0;
467  $textrating = $this->getTextRating();
468  foreach ($answers as $key => $value)
469  {
470  switch ($textrating)
471  {
473  if (strcmp(ilStr::strToLower($value), ilStr::strToLower($answer)) == 0 && $this->answers[$key]->getPoints() > 0) return $key;
474  break;
476  if (strcmp($value, $answer) == 0 && $this->answers[$key]->getPoints() > 0) return $key;
477  break;
479  if (levenshtein($value, $answer) <= 1 && $this->answers[$key]->getPoints() > 0) return $key;
480  break;
482  if (levenshtein($value, $answer) <= 2 && $this->answers[$key]->getPoints() > 0) return $key;
483  break;
485  if (levenshtein($value, $answer) <= 3 && $this->answers[$key]->getPoints() > 0) return $key;
486  break;
488  if (levenshtein($value, $answer) <= 4 && $this->answers[$key]->getPoints() > 0) return $key;
489  break;
491  if (levenshtein($value, $answer) <= 5 && $this->answers[$key]->getPoints() > 0) return $key;
492  break;
493  }
494  }
495  return FALSE;
496  }
497 
505  function getTextRating()
506  {
507  return $this->text_rating;
508  }
509 
517  function setTextRating($a_text_rating)
518  {
519  switch ($a_text_rating)
520  {
528  $this->text_rating = $a_text_rating;
529  break;
530  default:
531  $this->text_rating = TEXTGAP_RATING_CASEINSENSITIVE;
532  break;
533  }
534  }
535 
545  function calculateReachedPoints($active_id, $pass = NULL)
546  {
547  global $ilDB;
548 
549  $available_answers =& $this->getAvailableAnswers();
550  $found_counter = 0;
551 
552  if (is_null($pass))
553  {
554  $pass = $this->getSolutionMaxPass($active_id);
555  }
556  $result = $ilDB->queryF("SELECT * FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
557  array('integer','integer','integer'),
558  array($active_id, $this->getId(), $pass)
559  );
560  while ($data = $ilDB->fetchAssoc($result))
561  {
562  $enteredtext = $data["value1"];
563  $index = $this->isAnswerCorrect($available_answers, $enteredtext);
564  if ($index !== FALSE)
565  {
566  unset($available_answers[$index]);
567  $points += $this->answers[$index]->getPoints();
568  }
569  }
570 
571  $points = parent::calculateReachedPoints($active_id, $pass = NULL, $points);
572  return $points;
573  }
574 
581  function setCorrectAnswers($a_correct_answers)
582  {
583  $this->correctanswers = $a_correct_answers;
584  }
585 
592  function getCorrectAnswers()
593  {
594  return $this->correctanswers;
595  }
596 
605  function saveWorkingData($active_id, $pass = NULL)
606  {
607  global $ilDB;
608  global $ilUser;
609 
610  if (is_null($pass))
611  {
612  include_once "./Modules/Test/classes/class.ilObjTest.php";
613  $pass = ilObjTest::_getPass($active_id);
614  }
615  $entered_values = 0;
616 
617  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
618  array('integer','integer','integer'),
619  array($active_id, $this->getId(), $pass)
620  );
621  foreach ($_POST as $key => $value)
622  {
623  if (preg_match("/^TEXTSUBSET_(\d+)/", $key, $matches))
624  {
625  if (strlen($value))
626  {
627  $next_id = $ilDB->nextId('tst_solutions');
628  $affectedRows = $ilDB->insert("tst_solutions", array(
629  "solution_id" => array("integer", $next_id),
630  "active_fi" => array("integer", $active_id),
631  "question_fi" => array("integer", $this->getId()),
632  "value1" => array("clob", trim($value)),
633  "value2" => array("clob", null),
634  "pass" => array("integer", $pass),
635  "tstamp" => array("integer", time())
636  ));
637  $entered_values++;
638  }
639  }
640  }
641  if ($entered_values)
642  {
643  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
645  {
646  $this->logAction($this->lng->txtlng("assessment", "log_user_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
647  }
648  }
649  else
650  {
651  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
653  {
654  $this->logAction($this->lng->txtlng("assessment", "log_user_not_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
655  }
656  }
657  parent::saveWorkingData($active_id, $pass);
658  return true;
659  }
660 
667  function getQuestionType()
668  {
669  return "assTextSubset";
670  }
671 
678  function &joinAnswers()
679  {
680  $join = array();
681  foreach ($this->answers as $answer)
682  {
683  if (!is_array($join[$answer->getPoints() . ""]))
684  {
685  $join[$answer->getPoints() . ""] = array();
686  }
687  array_push($join[$answer->getPoints() . ""], $answer->getAnswertext());
688  }
689  return $join;
690  }
691 
699  {
700  $maxwidth = 0;
701  foreach ($this->answers as $answer)
702  {
703  $len = strlen($answer->getAnswertext());
704  if ($len > $maxwidth) $maxwidth = $len;
705  }
706  return $maxwidth + 3;
707  }
708 
716  {
717  return "qpl_qst_textsubset";
718  }
719 
727  {
728  return "qpl_a_textsubset";
729  }
730 
736  {
738  }
739 
752  public function setExportDetailsXLS(&$worksheet, $startrow, $active_id, $pass, &$format_title, &$format_bold)
753  {
754  include_once ("./Services/Excel/classes/class.ilExcelUtils.php");
755  $solutions = $this->getSolutionValues($active_id, $pass);
756  $worksheet->writeString($startrow, 0, ilExcelUtils::_convert_text($this->lng->txt($this->getQuestionType())), $format_title);
757  $worksheet->writeString($startrow, 1, ilExcelUtils::_convert_text($this->getTitle()), $format_title);
758  $i = 1;
759  foreach ($solutions as $solution)
760  {
761  $worksheet->write($startrow + $i, 0, ilExcelUtils::_convert_text($solution["value1"]));
762  $i++;
763  }
764  return $startrow + $i + 1;
765  }
766 
767  public function getAnswers()
768  {
769  return $this->answers;
770  }
771 
775  public function toJSON()
776  {
777  include_once("./Services/RTE/classes/class.ilRTE.php");
778  $result = array();
779  $result['id'] = (int) $this->getId();
780  $result['type'] = (string) $this->getQuestionType();
781  $result['title'] = (string) $this->getTitle();
782  $result['question'] = $this->formatSAQuestion($this->getQuestion());
783  $result['nr_of_tries'] = (int) $this->getNrOfTries();
784  $result['matching_method'] = (string) $this->getTextRating();
785  $result['feedback'] = array(
786  "onenotcorrect" => ilRTE::_replaceMediaObjectImageSrc($this->getFeedbackGeneric(0), 0),
787  "allcorrect" => ilRTE::_replaceMediaObjectImageSrc($this->getFeedbackGeneric(1), 0)
788  );
789 
790  $answers = array();
791  foreach ($this->getAnswers() as $key => $answer_obj)
792  {
793  array_push($answers, array(
794  "answertext" => (string) $answer_obj->getAnswertext(),
795  "points" => (float)$answer_obj->getPoints(),
796  "order" => (int)$answer_obj->getOrder()
797  ));
798  }
799  $result['correct_answers'] = $answers;
800 
801  $answers = array();
802  for($loop = 1; $loop <= (int) $this->getCorrectAnswers(); $loop++)
803  {
804  array_push($answers, array(
805  "answernr" => $loop
806  ));
807  }
808  $result['answers'] = $answers;
809 
810  $mobs = ilObjMediaObject::_getMobsOfObject("qpl:html", $this->getId());
811  $result['mobs'] = $mobs;
812 
813  return json_encode($result);
814  }
815 }
816 
817 ?>