ILIAS  Release_3_10_x_branch Revision 61812
 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 assTextSubset(
80  $title = "",
81  $comment = "",
82  $author = "",
83  $owner = -1,
84  $question = ""
85  )
86  {
88  $this->answers = array();
89  $this->correctanswers = 0;
90  }
91 
100  function isComplete()
101  {
102  if (($this->title) and ($this->author) and ($this->question) and (count($this->answers) >= $this->correctanswers) and ($this->getMaximumPoints() > 0))
103  {
104  return true;
105  }
106  else
107  {
108  return false;
109  }
110  }
111 
120  function saveToDb($original_id = "")
121  {
122  global $ilDB;
123 
124  $complete = 0;
125  if ($this->isComplete())
126  {
127  $complete = 1;
128  }
129  $estw_time = $this->getEstimatedWorkingTime();
130  $estw_time = sprintf("%02d:%02d:%02d", $estw_time['h'], $estw_time['m'], $estw_time['s']);
131 
132  if ($original_id)
133  {
134  $original_id = $ilDB->quote($original_id);
135  }
136  else
137  {
138  $original_id = "NULL";
139  }
140 
141  // cleanup RTE images which are not inserted into the question text
142  include_once("./Services/RTE/classes/class.ilRTE.php");
143  if ($this->id == -1)
144  {
145  // Neuen Datensatz schreiben
146  $now = getdate();
147  $question_type = $this->getQuestionTypeID();
148  $created = sprintf("%04d%02d%02d%02d%02d%02d", $now['year'], $now['mon'], $now['mday'], $now['hours'], $now['minutes'], $now['seconds']);
149  $query = sprintf("INSERT INTO qpl_questions (question_id, question_type_fi, obj_fi, title, comment, author, owner, question_text, points, working_time, complete, created, original_id, TIMESTAMP) VALUES (NULL, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, NULL)",
150  $ilDB->quote($question_type),
151  $ilDB->quote($this->obj_id),
152  $ilDB->quote($this->title),
153  $ilDB->quote($this->comment),
154  $ilDB->quote($this->author),
155  $ilDB->quote($this->owner),
156  $ilDB->quote(ilRTE::_replaceMediaObjectImageSrc($this->question, 0)),
157  $ilDB->quote($this->getMaximumPoints() . ""),
158  $ilDB->quote($estw_time),
159  $ilDB->quote("$complete"),
160  $ilDB->quote($created),
162  );
163  $result = $ilDB->query($query);
164 
165  if (PEAR::isError($result))
166  {
167  global $ilias;
168  $ilias->raiseError($result->getMessage());
169  }
170  else
171  {
172  $this->id = $ilDB->getLastInsertId();
173  $query = sprintf("INSERT INTO qpl_question_textsubset (question_fi, textgap_rating, correctanswers) VALUES (%s, %s, %s)",
174  $ilDB->quote($this->id . ""),
175  $ilDB->quote($this->getTextRating() . ""),
176  $ilDB->quote($this->getCorrectAnswers() . "")
177  );
178  $ilDB->query($query);
179 
180  // create page object of question
181  $this->createPageObject();
182 
183  // Falls die Frage in einen Test eingefügt werden soll, auch diese Verbindung erstellen
184  if ($this->getTestId() > 0)
185  {
186  $this->insertIntoTest($this->getTestId());
187  }
188  }
189  }
190  else
191  {
192  // Vorhandenen Datensatz aktualisieren
193  $query = sprintf("UPDATE qpl_questions SET obj_fi = %s, title = %s, comment = %s, author = %s, question_text = %s, points = %s, working_time=%s, complete = %s WHERE question_id = %s",
194  $ilDB->quote($this->obj_id. ""),
195  $ilDB->quote($this->title),
196  $ilDB->quote($this->comment),
197  $ilDB->quote($this->author),
198  $ilDB->quote(ilRTE::_replaceMediaObjectImageSrc($this->question, 0)),
199  $ilDB->quote($this->getMaximumPoints() . ""),
200  $ilDB->quote($estw_time),
201  $ilDB->quote("$complete"),
202  $ilDB->quote($this->id)
203  );
204  $result = $ilDB->query($query);
205  $query = sprintf("UPDATE qpl_question_textsubset SET textgap_rating = %s, correctanswers = %s WHERE question_fi = %s",
206  $ilDB->quote($this->getTextRating() . ""),
207  $ilDB->quote($this->getCorrectAnswers() . ""),
208  $ilDB->quote($this->id . "")
209  );
210  $result = $ilDB->query($query);
211  }
212  if (PEAR::isError($result))
213  {
214  global $ilias;
215  $ilias->raiseError($result->getMessage());
216  }
217  else
218  {
219  // Write Ranges to the database
220 
221  // 1. delete old ranges
222  $query = sprintf("DELETE FROM qpl_answer_textsubset WHERE question_fi = %s",
223  $ilDB->quote($this->id)
224  );
225  $result = $ilDB->query($query);
226 
227  // 2. write ranges
228  foreach ($this->answers as $key => $value)
229  {
230  $answer_obj = $this->answers[$key];
231  $query = sprintf("INSERT INTO qpl_answer_textsubset (answer_id, question_fi, answertext, points, aorder) VALUES (NULL, %s, %s, %s, %s)",
232  $ilDB->quote($this->id),
233  $ilDB->quote($answer_obj->getAnswertext()),
234  $ilDB->quote($answer_obj->getPoints() . ""),
235  $ilDB->quote($answer_obj->getOrder() . "")
236  );
237  $answer_result = $ilDB->query($query);
238  }
239  }
241  }
242 
252  function loadFromDb($question_id)
253  {
254  global $ilDB;
255 
256  $query = sprintf("SELECT qpl_questions.*, qpl_question_textsubset.* FROM qpl_questions, qpl_question_textsubset WHERE question_id = %s AND qpl_questions.question_id = qpl_question_textsubset.question_fi",
257  $ilDB->quote($question_id)
258  );
259  $result = $ilDB->query($query);
260  if ($result->numRows() == 1)
261  {
262  $data = $result->fetchRow(MDB2_FETCHMODE_OBJECT);
263  $this->id = $question_id;
264  $this->title = $data->title;
265  $this->comment = $data->comment;
266  $this->solution_hint = $data->solution_hint;
267  $this->original_id = $data->original_id;
268  $this->obj_id = $data->obj_fi;
269  $this->author = $data->author;
270  $this->owner = $data->owner;
271  $this->points = $data->points;
272  include_once("./Services/RTE/classes/class.ilRTE.php");
273  $this->question = ilRTE::_replaceMediaObjectImageSrc($data->question_text, 1);
274  $this->correctanswers = $data->correctanswers;
275  $this->text_rating = $data->textgap_rating;
276  $this->setEstimatedWorkingTime(substr($data->working_time, 0, 2), substr($data->working_time, 3, 2), substr($data->working_time, 6, 2));
277 
278  $query = sprintf("SELECT * FROM qpl_answer_textsubset WHERE question_fi = %s ORDER BY aorder ASC",
279  $ilDB->quote($question_id)
280  );
281  $result = $ilDB->query($query);
282 
283  include_once "./Modules/TestQuestionPool/classes/class.assAnswerSimple.php";
284  if ($result->numRows() > 0)
285  {
286  while ($data = $result->fetchRow(MDB2_FETCHMODE_ASSOC))
287  {
288  array_push($this->answers, new ASS_AnswerSimple($data["answertext"], $data["points"], $data["aorder"]));
289  }
290  }
291  }
292  parent::loadFromDb($question_id);
293  }
294 
302  function addAnswer($answertext, $points, $answerorder)
303  {
304  include_once "./Modules/TestQuestionPool/classes/class.assAnswerSimple.php";
305  array_push($this->answers, new ASS_AnswerSimple($answertext, $points, $answerorder));
306  }
307 
315  function duplicate($for_test = true, $title = "", $author = "", $owner = "")
316  {
317  if ($this->id <= 0)
318  {
319  // The question has not been saved. It cannot be duplicated
320  return;
321  }
322  // duplicate the question in database
323  $this_id = $this->getId();
324  $clone = $this;
325  include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
327  $clone->id = -1;
328  if ($title)
329  {
330  $clone->setTitle($title);
331  }
332 
333  if ($author)
334  {
335  $clone->setAuthor($author);
336  }
337  if ($owner)
338  {
339  $clone->setOwner($owner);
340  }
341 
342  if ($for_test)
343  {
344  $clone->saveToDb($original_id);
345  }
346  else
347  {
348  $clone->saveToDb();
349  }
350 
351  // copy question page content
352  $clone->copyPageOfQuestion($this_id);
353  // copy XHTML media objects
354  $clone->copyXHTMLMediaObjectsOfQuestion($this_id);
355  // duplicate the generic feedback
356  $clone->duplicateFeedbackGeneric($this_id);
357 
358  return $clone->id;
359  }
360 
368  function copyObject($target_questionpool, $title = "")
369  {
370  if ($this->id <= 0)
371  {
372  // The question has not been saved. It cannot be duplicated
373  return;
374  }
375  // duplicate the question in database
376  $clone = $this;
377  include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
379  $clone->id = -1;
380  $source_questionpool = $this->getObjId();
381  $clone->setObjId($target_questionpool);
382  if ($title)
383  {
384  $clone->setTitle($title);
385  }
386  $clone->saveToDb();
387 
388  // copy question page content
389  $clone->copyPageOfQuestion($original_id);
390  // copy XHTML media objects
391  $clone->copyXHTMLMediaObjectsOfQuestion($original_id);
392  // duplicate the generic feedback
393  $clone->duplicateFeedbackGeneric($original_id);
394 
395  return $clone->id;
396  }
397 
407  function getAnswerCount()
408  {
409  return count($this->answers);
410  }
411 
423  function getAnswer($index = 0)
424  {
425  if ($index < 0) return NULL;
426  if (count($this->answers) < 1) return NULL;
427  if ($index >= count($this->answers)) return NULL;
428 
429  return $this->answers[$index];
430  }
431 
442  function deleteAnswer($index = 0)
443  {
444  if ($index < 0) return;
445  if (count($this->answers) < 1) return;
446  if ($index >= count($this->answers)) return;
447  unset($this->answers[$index]);
448  $this->answers = array_values($this->answers);
449  for ($i = 0; $i < count($this->answers); $i++)
450  {
451  if ($this->answers[$i]->getOrder() > $index)
452  {
453  $this->answers[$i]->setOrder($i);
454  }
455  }
456  }
457 
466  function flushAnswers()
467  {
468  $this->answers = array();
469  }
470 
479  function getMaximumPoints()
480  {
481  $points = array();
482  foreach ($this->answers as $answer)
483  {
484  if ($answer->getPoints() > 0)
485  {
486  array_push($points, $answer->getPoints());
487  }
488  }
489  rsort($points, SORT_NUMERIC);
490  $maxpoints = 0;
491  for ($counter = 0; $counter < $this->getCorrectAnswers(); $counter++)
492  {
493  $maxpoints += $points[$counter];
494  }
495  return $maxpoints;
496  }
497 
507  {
508  $available_answers = array();
509  foreach ($this->answers as $answer)
510  {
511  array_push($available_answers, $answer->getAnswertext());
512  }
513  return $available_answers;
514  }
515 
528  function isAnswerCorrect($answers, $answer)
529  {
530  include_once "./Services/Utilities/classes/class.ilStr.php";
531  $result = 0;
532  $textrating = $this->getTextRating();
533  foreach ($answers as $key => $value)
534  {
535  switch ($textrating)
536  {
538  if (strcmp(ilStr::strToLower($value), ilStr::strToLower($answer)) == 0) return $key;
539  break;
541  if (strcmp($value, $answer) == 0) return $key;
542  break;
544  if (levenshtein($value, $answer) <= 1) return $key;
545  break;
547  if (levenshtein($value, $answer) <= 2) return $key;
548  break;
550  if (levenshtein($value, $answer) <= 3) return $key;
551  break;
553  if (levenshtein($value, $answer) <= 4) return $key;
554  break;
556  if (levenshtein($value, $answer) <= 5) return $key;
557  break;
558  }
559  }
560  return FALSE;
561  }
562 
572  function getTextRating()
573  {
574  return $this->text_rating;
575  }
576 
586  function setTextRating($a_text_rating)
587  {
588  switch ($a_text_rating)
589  {
597  $this->text_rating = $a_text_rating;
598  break;
599  default:
600  $this->text_rating = TEXTGAP_RATING_CASEINSENSITIVE;
601  break;
602  }
603  }
604 
616  function calculateReachedPoints($active_id, $pass = NULL)
617  {
618  global $ilDB;
619 
620  $available_answers =& $this->getAvailableAnswers();
621  $found_counter = 0;
622 
623  if (is_null($pass))
624  {
625  $pass = $this->getSolutionMaxPass($active_id);
626  }
627  $query = sprintf("SELECT * FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
628  $ilDB->quote($active_id . ""),
629  $ilDB->quote($this->getId() . ""),
630  $ilDB->quote($pass . "")
631  );
632  $result = $ilDB->query($query);
633  $points = 0;
634  while ($data = $result->fetchRow(MDB2_FETCHMODE_ASSOC))
635  {
636  $enteredtext = $data["value1"];
637  $index = $this->isAnswerCorrect($available_answers, $enteredtext);
638  if ($index !== FALSE)
639  {
640  unset($available_answers[$index]);
641  $points += $this->answers[$index]->getPoints();
642  }
643  }
644 
645  $points = parent::calculateReachedPoints($active_id, $pass = NULL, $points);
646  return $points;
647  }
648 
657  function setCorrectAnswers($a_correct_answers)
658  {
659  $this->correctanswers = $a_correct_answers;
660  }
661 
670  function getCorrectAnswers()
671  {
672  return $this->correctanswers;
673  }
674 
685  function saveWorkingData($active_id, $pass = NULL)
686  {
687  global $ilDB;
688  global $ilUser;
689 
690  if (is_null($pass))
691  {
692  include_once "./Modules/Test/classes/class.ilObjTest.php";
693  $pass = ilObjTest::_getPass($active_id);
694  }
695  $entered_values = 0;
696 
697  $query = sprintf("DELETE FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
698  $ilDB->quote($active_id . ""),
699  $ilDB->quote($this->getId() . ""),
700  $ilDB->quote($pass . "")
701  );
702  $result = $ilDB->query($query);
703  foreach ($_POST as $key => $value)
704  {
705  if (preg_match("/^TEXTSUBSET_(\d+)/", $key, $matches))
706  {
707  if (strlen($value))
708  {
709  $query = sprintf("INSERT INTO tst_solutions (solution_id, active_fi, question_fi, value1, value2, pass, TIMESTAMP) VALUES (NULL, %s, %s, %s, NULL, %s, NULL)",
710  $ilDB->quote($active_id),
711  $ilDB->quote($this->getId()),
712  $ilDB->quote(trim($value)),
713  $ilDB->quote($pass . "")
714  );
715  $result = $ilDB->query($query);
716  $entered_values++;
717  }
718  }
719  }
720  if ($entered_values)
721  {
722  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
724  {
725  $this->logAction($this->lng->txtlng("assessment", "log_user_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
726  }
727  }
728  else
729  {
730  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
732  {
733  $this->logAction($this->lng->txtlng("assessment", "log_user_not_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
734  }
735  }
736  parent::saveWorkingData($active_id, $pass);
737  return true;
738  }
739 
748  function getQuestionType()
749  {
750  return "assTextSubset";
751  }
752 
761  function &joinAnswers()
762  {
763  $join = array();
764  foreach ($this->answers as $answer)
765  {
766  if (!is_array($join[$answer->getPoints() . ""]))
767  {
768  $join[$answer->getPoints() . ""] = array();
769  }
770  array_push($join[$answer->getPoints() . ""], $answer->getAnswertext());
771  }
772  return $join;
773  }
774 
784  {
785  $maxwidth = 0;
786  foreach ($this->answers as $answer)
787  {
788  $len = strlen($answer->getAnswertext());
789  if ($len > $maxwidth) $maxwidth = $len;
790  }
791  return $maxwidth + 3;
792  }
793 
803  {
804  return "qpl_question_textsubset";
805  }
806 
816  {
817  return "qpl_answer_textsubset";
818  }
819 
825  {
827  }
828 
841  public function setExportDetailsXLS(&$worksheet, $startrow, $active_id, $pass, &$format_title, &$format_bold)
842  {
843  include_once ("./classes/class.ilExcelUtils.php");
844  $solutions = $this->getSolutionValues($active_id, $pass);
845  $worksheet->writeString($startrow, 0, ilExcelUtils::_convert_text($this->lng->txt($this->getQuestionType())), $format_title);
846  $worksheet->writeString($startrow, 1, ilExcelUtils::_convert_text($this->getTitle()), $format_title);
847  $i = 1;
848  foreach ($solutions as $solution)
849  {
850  $worksheet->write($startrow + $i, 0, ilExcelUtils::_convert_text($solution["value1"]));
851  $i++;
852  }
853  return $startrow + $i + 1;
854  }
855 }
856 
857 ?>