ILIAS  Release_3_10_x_branch Revision 61812
 All Data Structures Namespaces Files Functions Variables Groups Pages
class.assTextQuestion.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 
36 {
45 
54  var $keywords;
55 
64 
78  function assTextQuestion(
79  $title = "",
80  $comment = "",
81  $author = "",
82  $owner = -1,
83  $question = ""
84  )
85  {
87  $this->maxNumOfChars = 0;
88  $this->points = 0;
89  $this->keywords = "";
90  }
91 
100  function isComplete()
101  {
102  if (($this->title) and ($this->author) and ($this->question) 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, points, question_text, 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($this->getPoints() . ""),
157  $ilDB->quote(ilRTE::_replaceMediaObjectImageSrc($this->question, 0)),
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_essay (question_fi, maxNumOfChars, keywords, textgap_rating) VALUES (%s, %s, %s, %s)",
174  $ilDB->quote($this->id . ""),
175  $ilDB->quote($this->getMaxNumOfChars()),
176  $ilDB->quote($this->getKeywords() . ""),
177  $ilDB->quote($this->getTextRating() . "")
178  );
179  $ilDB->query($query);
180 
181  // create page object of question
182  $this->createPageObject();
183 
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, points = %s, question_text = %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($this->getPoints() . ""),
199  $ilDB->quote(ilRTE::_replaceMediaObjectImageSrc($this->question, 0)),
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_essay SET maxNumOfChars = %s, keywords = %s, textgap_rating = %s WHERE question_fi = %s",
206  $ilDB->quote($this->getMaxNumOfChars()),
207  $ilDB->quote($this->getKeywords() . ""),
208  $ilDB->quote($this->getTextRating() . ""),
209  $ilDB->quote($this->id . "")
210  );
211  $result = $ilDB->query($query);
212  }
214  }
215 
225  function loadFromDb($question_id)
226  {
227  global $ilDB;
228 
229  $query = sprintf("SELECT qpl_questions.*, qpl_question_essay.* FROM qpl_questions, qpl_question_essay WHERE question_id = %s AND qpl_questions.question_id = qpl_question_essay.question_fi",
230  $ilDB->quote($question_id)
231  );
232  $result = $ilDB->query($query);
233  if ($result->numRows() == 1)
234  {
235  $data = $result->fetchRow(MDB2_FETCHMODE_OBJECT);
236  $this->id = $question_id;
237  $this->title = $data->title;
238  $this->comment = $data->comment;
239  $this->solution_hint = $data->solution_hint;
240  $this->original_id = $data->original_id;
241  $this->obj_id = $data->obj_fi;
242  $this->author = $data->author;
243  $this->owner = $data->owner;
244  include_once("./Services/RTE/classes/class.ilRTE.php");
245  $this->question = ilRTE::_replaceMediaObjectImageSrc($data->question_text, 1);
246  $this->maxNumOfChars = $data->maxNumOfChars;
247  $this->keywords = $data->keywords;
248  $this->text_rating = $data->textgap_rating;
249  $this->points = $data->points;
250  $this->setEstimatedWorkingTime(substr($data->working_time, 0, 2), substr($data->working_time, 3, 2), substr($data->working_time, 6, 2));
251  }
252  parent::loadFromDb($question_id);
253  }
254 
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 
305  return $clone->id;
306  }
307 
315  function copyObject($target_questionpool, $title = "")
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  $clone = $this;
324  include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
326  $clone->id = -1;
327  $source_questionpool = $this->getObjId();
328  $clone->setObjId($target_questionpool);
329  if ($title)
330  {
331  $clone->setTitle($title);
332  }
333  $clone->saveToDb();
334 
335  // copy question page content
336  $clone->copyPageOfQuestion($original_id);
337  // copy XHTML media objects
338  $clone->copyXHTMLMediaObjectsOfQuestion($original_id);
339  // duplicate the generic feedback
340  $clone->duplicateFeedbackGeneric($original_id);
341 
342  return $clone->id;
343  }
344 
354  function getMaxNumOfChars()
355  {
356  if (strcmp($this->maxNumOfChars, "") == 0)
357  {
358  return 0;
359  }
360  else
361  {
362  return $this->maxNumOfChars;
363  }
364  }
365 
375  function setMaxNumOfChars($maxchars = 0)
376  {
377  $this->maxNumOfChars = $maxchars;
378  }
379 
388  function getMaximumPoints()
389  {
390  return $this->points;
391  }
392 
404  function setReachedPoints($active_id, $points, $pass = NULL)
405  {
406  global $ilDB;
407 
408  if (($points > 0) && ($points <= $this->getPoints()))
409  {
410  if (is_null($pass))
411  {
412  $pass = $this->getSolutionMaxPass($active_id);
413  }
414  $query = sprintf("UPDATE tst_test_result SET points = %s WHERE active_fi = %s AND question_fi = %s AND pass = %s",
415  $ilDB->quote($points . ""),
416  $ilDB->quote($active_id . ""),
417  $ilDB->quote($this->getId() . ""),
418  $ilDB->quote($pass . "")
419  );
420  $result = $ilDB->query($query);
421  $this->_updateTestPassResults($active_id, $pass);
422  return TRUE;
423  }
424  else
425  {
426  return TRUE;
427  }
428  }
429 
440  function isKeywordMatching($answertext, $a_keyword)
441  {
442  $result = FALSE;
443  $textrating = $this->getTextRating();
444  include_once "./Services/Utilities/classes/class.ilStr.php";
445  switch ($textrating)
446  {
448  if (ilStr::strPos(ilStr::strToLower($answertext), ilStr::strToLower($a_keyword)) !== false) return TRUE;
449  break;
451  if (ilStr::strPos($answertext, $a_keyword) !== false) return TRUE;
452  break;
453  }
454  $answerwords = array();
455  if (preg_match_all("/([^\s.]+)/", $answertext, $matches))
456  {
457  foreach ($matches[1] as $answerword)
458  {
459  array_push($answerwords, trim($answerword));
460  }
461  }
462  foreach ($answerwords as $a_original)
463  {
464  switch ($textrating)
465  {
467  if (levenshtein($a_original, $a_keyword) <= 1) return TRUE;
468  break;
470  if (levenshtein($a_original, $a_keyword) <= 2) return TRUE;
471  break;
473  if (levenshtein($a_original, $a_keyword) <= 3) return TRUE;
474  break;
476  if (levenshtein($a_original, $a_keyword) <= 4) return TRUE;
477  break;
479  if (levenshtein($a_original, $a_keyword) <= 5) return TRUE;
480  break;
481  }
482  }
483  return $result;
484  }
485 
497  function calculateReachedPoints($active_id, $pass = NULL)
498  {
499  global $ilDB;
500 
501  $points = 0;
502  if (is_null($pass))
503  {
504  $pass = $this->getSolutionMaxPass($active_id);
505  }
506  $query = sprintf("SELECT * FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
507  $ilDB->quote($active_id . ""),
508  $ilDB->quote($this->getId() . ""),
509  $ilDB->quote($pass . "")
510  );
511  $result = $ilDB->query($query);
512  if ($result->numRows() == 1)
513  {
514  $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
515  if ($row["points"])
516  {
517  $points = $row["points"];
518  }
519  else
520  {
521  $keywords =& $this->getKeywordList();
522  if (count($keywords))
523  {
524  $foundkeyword = false;
525  foreach ($keywords as $keyword)
526  {
527  if (!$foundkeyword)
528  {
529  if ($this->isKeywordMatching($row["value1"], $keyword))
530  {
531  $foundkeyword = true;
532  }
533  }
534  }
535  if ($foundkeyword) $points = $this->getMaximumPoints();
536  }
537  }
538  }
539 
540  $points = parent::calculateReachedPoints($active_id, $pass = NULL, $points);
541  return $points;
542  }
543 
554  function saveWorkingData($active_id, $pass = NULL)
555  {
556  global $ilDB;
557  global $ilUser;
558 
559  if (is_null($pass))
560  {
561  include_once "./Modules/Test/classes/class.ilObjTest.php";
562  $pass = ilObjTest::_getPass($active_id);
563  }
564  $query = sprintf("DELETE FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
565  $ilDB->quote($active_id . ""),
566  $ilDB->quote($this->getId() . ""),
567  $ilDB->quote($pass . "")
568  );
569  $result = $ilDB->query($query);
570  $text = ilUtil::stripSlashes($_POST["TEXT"], FALSE);
571  if ($this->getMaxNumOfChars())
572  {
573  include_once "./Services/Utilities/classes/class.ilStr.php";
574  $text_without_tags = preg_replace("/<[^>*?]>/is", "", $text);
575  $len_with_tags = ilStr::strLen($text);
576  $len_without_tags = ilStr::strLen($text_without_tags);
577  if ($this->getMaxNumOfChars() < $len_without_tags)
578  {
579  if (!$this->isHTML($text))
580  {
581  $text = ilStr::subStr($text, 0, $this->getMaxNumOfChars());
582  }
583  else
584  {
585  // this often produces bad XHTML which leads to problems with PDF export
586  // a cleanup must be made
587  // $text = ilStr::subStr($text, 0, $this->getMaxNumOfChars() + ($len_with_tags - $len_without_tags));
588  }
589  }
590  }
591  if ($this->isHTML($text))
592  {
593  $text = preg_replace("/<[^>]*$/ims", "", $text);
594  }
595  else
596  {
597  //$text = htmlentities($text, ENT_QUOTES, "UTF-8");
598  }
599  $entered_values = 0;
600  if (strlen($text))
601  {
602  $query = sprintf("INSERT INTO tst_solutions (solution_id, active_fi, question_fi, value1, value2, pass, TIMESTAMP) VALUES (NULL, %s, %s, %s, NULL, %s, NULL)",
603  $ilDB->quote($active_id . ""),
604  $ilDB->quote($this->getId() . ""),
605  $ilDB->quote(trim($text) . ""),
606  $ilDB->quote($pass . "")
607  );
608  $result = $ilDB->query($query);
609  $entered_values++;
610  }
611  if ($entered_values)
612  {
613  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
615  {
616  $this->logAction($this->lng->txtlng("assessment", "log_user_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
617  }
618  }
619  else
620  {
621  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
623  {
624  $this->logAction($this->lng->txtlng("assessment", "log_user_not_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
625  }
626  }
627  parent::saveWorkingData($active_id, $pass);
628  return true;
629  }
630 
631  function createRandomSolution($test_id, $user_id)
632  {
633  }
634 
643  function getQuestionType()
644  {
645  return "assTextQuestion";
646  }
647 
656  function getKeywords()
657  {
658  return $this->keywords;
659  }
660 
669  function setKeywords($a_keywords)
670  {
671  $this->keywords = $a_keywords;
672  }
673 
682  function &getKeywordList()
683  {
684  $keywords = array();
685  if (preg_match_all("/([^\s]+)/", $this->keywords, $matches))
686  {
687  foreach ($matches[1] as $keyword)
688  {
689  array_push($keywords, trim($keyword));
690  }
691  }
692  return $keywords;
693  }
694 
704  function getTextRating()
705  {
706  return $this->text_rating;
707  }
708 
718  function setTextRating($a_text_rating)
719  {
720  switch ($a_text_rating)
721  {
729  $this->text_rating = $a_text_rating;
730  break;
731  default:
732  $this->text_rating = TEXTGAP_RATING_CASEINSENSITIVE;
733  break;
734  }
735  }
736 
746  {
747  return "qpl_question_essay";
748  }
749 
755  {
757  }
758 
771  public function setExportDetailsXLS(&$worksheet, $startrow, $active_id, $pass, &$format_title, &$format_bold)
772  {
773  include_once ("./classes/class.ilExcelUtils.php");
774  $solutions = $this->getSolutionValues($active_id, $pass);
775  $worksheet->writeString($startrow, 0, ilExcelUtils::_convert_text($this->lng->txt($this->getQuestionType())), $format_title);
776  $worksheet->writeString($startrow, 1, ilExcelUtils::_convert_text($this->getTitle()), $format_title);
777  $i = 1;
778  $worksheet->writeString($startrow + $i, 0, ilExcelUtils::_convert_text($this->lng->txt("result")), $format_bold);
779  if (strlen($solutions[0]["value1"]))
780  {
781  $worksheet->write($startrow + $i, 1, ilExcelUtils::_convert_text($solutions[0]["value1"]));
782  }
783  $i++;
784  return $startrow + $i + 1;
785  }
786 }
787 
788 ?>