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 
38 {
46  var $answers;
47 
56 
63 
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 ########
136  $affectedRows = $ilDB->manipulateF("INSERT INTO " . $this->getAdditionalTableName() . " (question_fi, textgap_rating, correctanswers, answerscount) VALUES (%s, %s, %s, %s)",
137  array("integer", "text", "integer", "integer"),
138  array(
139  $this->getId(),
140  $this->getTextRating(),
141  $this->getCorrectAnswers(),
142  $this->getAnswersCount()
143  )
144  );
145 
146  $affectedRows = $ilDB->manipulateF("DELETE FROM qpl_a_textsubset WHERE question_fi = %s",
147  array('integer'),
148  array($this->getId())
149  );
150 
151  foreach ($this->answers as $key => $value)
152  {
153  $answer_obj = $this->answers[$key];
154  $next_id = $ilDB->nextId('qpl_a_textsubset');
155  $query = $ilDB->manipulateF("INSERT INTO qpl_a_textsubset (answer_id, question_fi, answertext, points, aorder, tstamp) VALUES (%s, %s, %s, %s, %s, %s)",
156  array('integer', 'integer', 'text', 'float', 'integer', 'integer'),
157  array(
158  $next_id,
159  $this->getId(),
160  $answer_obj->getAnswertext(),
161  $answer_obj->getPoints(),
162  $answer_obj->getOrder(),
163  time()
164  )
165  );
166  }
167 
169  }
170 
178  function loadFromDb($question_id)
179  {
180  global $ilDB;
181 
182  $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",
183  array("integer"),
184  array($question_id)
185  );
186  if ($result->numRows() == 1)
187  {
188  $data = $ilDB->fetchAssoc($result);
189  $this->setId($question_id);
190  $this->setObjId($data["obj_fi"]);
191  $this->setNrOfTries($data['nr_of_tries']);
192  $this->setTitle($data["title"]);
193  $this->setComment($data["description"]);
194  $this->setOriginalId($data["original_id"]);
195  $this->setAuthor($data["author"]);
196  $this->setPoints($data["points"]);
197  $this->setOwner($data["owner"]);
198  include_once("./Services/RTE/classes/class.ilRTE.php");
199  $this->setQuestion(ilRTE::_replaceMediaObjectImageSrc($data["question_text"], 1));
200  $this->setCorrectAnswers($data["correctanswers"]);
201 
202  $this->answerscount = $data["answerscount"];
203  $this->setTextRating($data["textgap_rating"]);
204  $this->setEstimatedWorkingTime(substr($data["working_time"], 0, 2), substr($data["working_time"], 3, 2), substr($data["working_time"], 6, 2));
205  }
206 
207 
208  $result = $ilDB->queryF("SELECT * FROM qpl_a_textsubset WHERE question_fi = %s ORDER BY aorder ASC",
209  array('integer'),
210  array($question_id)
211  );
212  include_once "./Modules/TestQuestionPool/classes/class.assAnswerBinaryStateImage.php";
213  if ($result->numRows() > 0)
214  {
215  while ($data = $ilDB->fetchAssoc($result))
216  {
217  array_push($this->answers, new ASS_AnswerBinaryStateImage($data["answertext"], $data["points"], $data["aorder"]));
218  }
219  }
220 
221  parent::loadFromDb($question_id);
222  }
223 
229  function addAnswer($answertext, $points, $order)
230  {
231  include_once "./Modules/TestQuestionPool/classes/class.assAnswerBinaryStateImage.php";
232  if (array_key_exists($order, $this->answers))
233  {
234  // insert answer
235  $answer = new ASS_AnswerBinaryStateImage($answertext, $points, $order);
236  $newchoices = array();
237  for ($i = 0; $i < $order; $i++)
238  {
239  array_push($newchoices, $this->answers[$i]);
240  }
241  array_push($newchoices, $answer);
242  for ($i = $order; $i < count($this->answers); $i++)
243  {
244  $changed = $this->answers[$i];
245  $changed->setOrder($i+1);
246  array_push($newchoices, $changed);
247  }
248  $this->answers = $newchoices;
249  }
250  else
251  {
252  // add answer
253  array_push($this->answers, new ASS_AnswerBinaryStateImage($answertext, $points, count($this->answers)));
254  }
255  }
256 
262  function duplicate($for_test = true, $title = "", $author = "", $owner = "")
263  {
264  if ($this->id <= 0)
265  {
266  // The question has not been saved. It cannot be duplicated
267  return;
268  }
269  // duplicate the question in database
270  $this_id = $this->getId();
271  $clone = $this;
272  include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
274  $clone->id = -1;
275  if ($title)
276  {
277  $clone->setTitle($title);
278  }
279 
280  if ($author)
281  {
282  $clone->setAuthor($author);
283  }
284  if ($owner)
285  {
286  $clone->setOwner($owner);
287  }
288 
289  if ($for_test)
290  {
291  $clone->saveToDb($original_id);
292  }
293  else
294  {
295  $clone->saveToDb();
296  }
297 
298  // copy question page content
299  $clone->copyPageOfQuestion($this_id);
300  // copy XHTML media objects
301  $clone->copyXHTMLMediaObjectsOfQuestion($this_id);
302  // duplicate the generic feedback
303  $clone->duplicateFeedbackGeneric($this_id);
304  $clone->onDuplicate($this_id);
305 
306  return $clone->id;
307  }
308 
314  function copyObject($target_questionpool, $title = "")
315  {
316  if ($this->id <= 0)
317  {
318  // The question has not been saved. It cannot be duplicated
319  return;
320  }
321  // duplicate the question in database
322  $clone = $this;
323  include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
325  $clone->id = -1;
326  $source_questionpool = $this->getObjId();
327  $clone->setObjId($target_questionpool);
328  if ($title)
329  {
330  $clone->setTitle($title);
331  }
332  $clone->saveToDb();
333 
334  // copy question page content
335  $clone->copyPageOfQuestion($original_id);
336  // copy XHTML media objects
337  $clone->copyXHTMLMediaObjectsOfQuestion($original_id);
338  // duplicate the generic feedback
339  $clone->duplicateFeedbackGeneric($original_id);
340  $clone->onCopy($this->getObjId(), $this->getId());
341 
342  return $clone->id;
343  }
344 
352  function getAnswerCount()
353  {
354  return count($this->answers);
355  }
356 
366  function getAnswer($index = 0)
367  {
368  if ($index < 0) return NULL;
369  if (count($this->answers) < 1) return NULL;
370  if ($index >= count($this->answers)) return NULL;
371 
372  return $this->answers[$index];
373  }
374 
383  function deleteAnswer($index = 0)
384  {
385  if ($index < 0) return;
386  if (count($this->answers) < 1) return;
387  if ($index >= count($this->answers)) return;
388  unset($this->answers[$index]);
389  $this->answers = array_values($this->answers);
390  for ($i = 0; $i < count($this->answers); $i++)
391  {
392  if ($this->answers[$i]->getOrder() > $index)
393  {
394  $this->answers[$i]->setOrder($i);
395  }
396  }
397  }
398 
405  function flushAnswers()
406  {
407  $this->answers = array();
408  }
409 
416  function getMaximumPoints()
417  {
418  $points = array();
419  foreach ($this->answers as $answer)
420  {
421  if ($answer->getPoints() > 0)
422  {
423  array_push($points, $answer->getPoints());
424  }
425  }
426  rsort($points, SORT_NUMERIC);
427  $maxpoints = 0;
428  for ($counter = 0; $counter < $this->getCorrectAnswers(); $counter++)
429  {
430  $maxpoints += $points[$counter];
431  }
432  return $maxpoints;
433  }
434 
442  {
443  $available_answers = array();
444  foreach ($this->answers as $answer)
445  {
446  array_push($available_answers, $answer->getAnswertext());
447  }
448  return $available_answers;
449  }
450 
461  function isAnswerCorrect($answers, $answer)
462  {
463  include_once "./Services/Utilities/classes/class.ilStr.php";
464  $result = 0;
465  $textrating = $this->getTextRating();
466  foreach ($answers as $key => $value)
467  {
468  switch ($textrating)
469  {
471  if (strcmp(ilStr::strToLower($value), ilStr::strToLower($answer)) == 0) return $key;
472  break;
474  if (strcmp($value, $answer) == 0) return $key;
475  break;
477  if (levenshtein($value, $answer) <= 1) return $key;
478  break;
480  if (levenshtein($value, $answer) <= 2) return $key;
481  break;
483  if (levenshtein($value, $answer) <= 3) return $key;
484  break;
486  if (levenshtein($value, $answer) <= 4) return $key;
487  break;
489  if (levenshtein($value, $answer) <= 5) return $key;
490  break;
491  }
492  }
493  return FALSE;
494  }
495 
503  function getTextRating()
504  {
505  return $this->text_rating;
506  }
507 
515  function setTextRating($a_text_rating)
516  {
517  switch ($a_text_rating)
518  {
526  $this->text_rating = $a_text_rating;
527  break;
528  default:
529  $this->text_rating = TEXTGAP_RATING_CASEINSENSITIVE;
530  break;
531  }
532  }
533 
543  function calculateReachedPoints($active_id, $pass = NULL)
544  {
545  global $ilDB;
546 
547  $available_answers =& $this->getAvailableAnswers();
548  $found_counter = 0;
549 
550  if (is_null($pass))
551  {
552  $pass = $this->getSolutionMaxPass($active_id);
553  }
554  $result = $ilDB->queryF("SELECT * FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
555  array('integer','integer','integer'),
556  array($active_id, $this->getId(), $pass)
557  );
558  while ($data = $ilDB->fetchAssoc($result))
559  {
560  $enteredtext = $data["value1"];
561  $index = $this->isAnswerCorrect($available_answers, $enteredtext);
562  if ($index !== FALSE)
563  {
564  unset($available_answers[$index]);
565  $points += $this->answers[$index]->getPoints();
566  }
567  }
568 
569  $points = parent::calculateReachedPoints($active_id, $pass = NULL, $points);
570  return $points;
571  }
572 
579  function setCorrectAnswers($a_correct_answers)
580  {
581  $this->correctanswers = $a_correct_answers;
582  }
583 
590  function getCorrectAnswers()
591  {
592  return $this->correctanswers;
593  }
594 
601  function getAnswersCount()
602  {
603  return $this->answerscount;
604  }
605 
614  function saveWorkingData($active_id, $pass = NULL)
615  {
616  global $ilDB;
617  global $ilUser;
618 
619  if (is_null($pass))
620  {
621  include_once "./Modules/Test/classes/class.ilObjTest.php";
622  $pass = ilObjTest::_getPass($active_id);
623  }
624  $entered_values = 0;
625 
626  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
627  array('integer','integer','integer'),
628  array($active_id, $this->getId(), $pass)
629  );
630  foreach ($_POST as $key => $value)
631  {
632  if (preg_match("/^TEXTSUBSET_(\d+)/", $key, $matches))
633  {
634  if (strlen($value))
635  {
636  $next_id = $ilDB->nextId('tst_solutions');
637  $affectedRows = $ilDB->insert("tst_solutions", array(
638  "solution_id" => array("integer", $next_id),
639  "active_fi" => array("integer", $active_id),
640  "question_fi" => array("integer", $this->getId()),
641  "value1" => array("clob", trim($value)),
642  "value2" => array("clob", null),
643  "pass" => array("integer", $pass),
644  "tstamp" => array("integer", time())
645  ));
646  $entered_values++;
647  }
648  }
649  }
650  if ($entered_values)
651  {
652  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
654  {
655  $this->logAction($this->lng->txtlng("assessment", "log_user_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
656  }
657  }
658  else
659  {
660  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
662  {
663  $this->logAction($this->lng->txtlng("assessment", "log_user_not_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
664  }
665  }
666  parent::saveWorkingData($active_id, $pass);
667  return true;
668  }
669 
676  function getQuestionType()
677  {
678  return "assTextSubset";
679  }
680 
687  function &joinAnswers()
688  {
689  $join = array();
690  foreach ($this->answers as $answer)
691  {
692  if (!is_array($join[$answer->getPoints() . ""]))
693  {
694  $join[$answer->getPoints() . ""] = array();
695  }
696  array_push($join[$answer->getPoints() . ""], $answer->getAnswertext());
697  }
698  return $join;
699  }
700 
708  {
709  $maxwidth = 0;
710  foreach ($this->answers as $answer)
711  {
712  $len = strlen($answer->getAnswertext());
713  if ($len > $maxwidth) $maxwidth = $len;
714  }
715  return $maxwidth + 3;
716  }
717 
725  {
726  return "qpl_qst_textsubset";
727  }
728 
736  {
737  return "qpl_a_textsubset";
738  }
739 
745  {
747  }
748 
761  public function setExportDetailsXLS(&$worksheet, $startrow, $active_id, $pass, &$format_title, &$format_bold)
762  {
763  include_once ("./Services/Excel/classes/class.ilExcelUtils.php");
764  $solutions = $this->getSolutionValues($active_id, $pass);
765  $worksheet->writeString($startrow, 0, ilExcelUtils::_convert_text($this->lng->txt($this->getQuestionType())), $format_title);
766  $worksheet->writeString($startrow, 1, ilExcelUtils::_convert_text($this->getTitle()), $format_title);
767  $i = 1;
768  foreach ($solutions as $solution)
769  {
770  $worksheet->write($startrow + $i, 0, ilExcelUtils::_convert_text($solution["value1"]));
771  $i++;
772  }
773  return $startrow + $i + 1;
774  }
775 
776  public function getAnswers()
777  {
778  return $this->answers;
779  }
780 }
781 
782 ?>