ILIAS  Release_4_0_x_branch Revision 61816
 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 
62 
76  function __construct(
77  $title = "",
78  $comment = "",
79  $author = "",
80  $owner = -1,
81  $question = ""
82  )
83  {
85  $this->maxNumOfChars = 0;
86  $this->points = 0;
87  $this->keywords = "";
88  }
89 
96  function isComplete()
97  {
98  if (($this->title) and ($this->author) and ($this->question) and ($this->getMaximumPoints() > 0))
99  {
100  return true;
101  }
102  else
103  {
104  return false;
105  }
106  }
107 
114  function saveToDb($original_id = "")
115  {
116  global $ilDB;
117 
119 
120  // save additional data
121  $affectedRows = $ilDB->manipulateF("DELETE FROM " . $this->getAdditionalTableName() . " WHERE question_fi = %s",
122  array("integer"),
123  array($this->getId())
124  );
125 
126  $affectedRows = $ilDB->manipulateF("INSERT INTO " . $this->getAdditionalTableName() . " (question_fi, maxnumofchars, keywords, textgap_rating) VALUES (%s, %s, %s, %s)",
127  array("integer", "integer", "text", "text"),
128  array(
129  $this->getId(),
130  $this->getMaxNumOfChars(),
131  (strlen($this->getKeywords())) ? $this->getKeywords() : NULL,
132  $this->getTextRating()
133  )
134  );
135 
137  }
138 
146  function loadFromDb($question_id)
147  {
148  global $ilDB;
149 
150  $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",
151  array("integer"),
152  array($question_id)
153  );
154  if ($result->numRows() == 1)
155  {
156  $data = $ilDB->fetchAssoc($result);
157  $this->setId($question_id);
158  $this->setObjId($data["obj_fi"]);
159  $this->setTitle($data["title"]);
160  $this->setComment($data["description"]);
161  $this->setOriginalId($data["original_id"]);
162  $this->setNrOfTries($data['nr_of_tries']);
163  $this->setAuthor($data["author"]);
164  $this->setPoints($data["points"]);
165  $this->setOwner($data["owner"]);
166  include_once("./Services/RTE/classes/class.ilRTE.php");
167  $this->setQuestion(ilRTE::_replaceMediaObjectImageSrc($data["question_text"], 1));
168  $this->setShuffle($data["shuffle"]);
169  $this->setMaxNumOfChars($data["maxnumofchars"]);
170  $this->setKeywords($data["keywords"]);
171  $this->setTextRating($data["textgap_rating"]);
172  $this->setEstimatedWorkingTime(substr($data["working_time"], 0, 2), substr($data["working_time"], 3, 2), substr($data["working_time"], 6, 2));
173  }
174  parent::loadFromDb($question_id);
175  }
176 
182  function duplicate($for_test = true, $title = "", $author = "", $owner = "")
183  {
184  if ($this->id <= 0)
185  {
186  // The question has not been saved. It cannot be duplicated
187  return;
188  }
189  // duplicate the question in database
190  $this_id = $this->getId();
191  $clone = $this;
192  include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
194  $clone->id = -1;
195  if ($title)
196  {
197  $clone->setTitle($title);
198  }
199 
200  if ($author)
201  {
202  $clone->setAuthor($author);
203  }
204  if ($owner)
205  {
206  $clone->setOwner($owner);
207  }
208 
209  if ($for_test)
210  {
211  $clone->saveToDb($original_id);
212  }
213  else
214  {
215  $clone->saveToDb();
216  }
217 
218  // copy question page content
219  $clone->copyPageOfQuestion($this_id);
220  // copy XHTML media objects
221  $clone->copyXHTMLMediaObjectsOfQuestion($this_id);
222  // duplicate the generic feedback
223  $clone->duplicateFeedbackGeneric($this_id);
224  $clone->onDuplicate($this_id);
225 
226  return $clone->id;
227  }
228 
234  function copyObject($target_questionpool, $title = "")
235  {
236  if ($this->id <= 0)
237  {
238  // The question has not been saved. It cannot be duplicated
239  return;
240  }
241  // duplicate the question in database
242  $clone = $this;
243  include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
245  $clone->id = -1;
246  $source_questionpool = $this->getObjId();
247  $clone->setObjId($target_questionpool);
248  if ($title)
249  {
250  $clone->setTitle($title);
251  }
252  $clone->saveToDb();
253 
254  // copy question page content
255  $clone->copyPageOfQuestion($original_id);
256  // copy XHTML media objects
257  $clone->copyXHTMLMediaObjectsOfQuestion($original_id);
258  // duplicate the generic feedback
259  $clone->duplicateFeedbackGeneric($original_id);
260  $clone->onCopy($this->getObjId(), $this->getId());
261 
262  return $clone->id;
263  }
264 
272  function getMaxNumOfChars()
273  {
274  if (strcmp($this->maxNumOfChars, "") == 0)
275  {
276  return 0;
277  }
278  else
279  {
280  return $this->maxNumOfChars;
281  }
282  }
283 
291  function setMaxNumOfChars($maxchars = 0)
292  {
293  $this->maxNumOfChars = $maxchars;
294  }
295 
302  function getMaximumPoints()
303  {
304  return $this->points;
305  }
306 
316  function setReachedPoints($active_id, $points, $pass = NULL)
317  {
318  global $ilDB;
319 
320  if (($points > 0) && ($points <= $this->getPoints()))
321  {
322  if (is_null($pass))
323  {
324  $pass = $this->getSolutionMaxPass($active_id);
325  }
326  $affectedRows = $ilDB->manipulateF("UPDATE tst_test_result SET points = %s WHERE active_fi = %s AND question_fi = %s AND pass = %s",
327  array('float','integer','integer','integer'),
328  array($points, $active_id, $this->getId(), $pass)
329  );
330  $this->_updateTestPassResults($active_id, $pass);
331  return TRUE;
332  }
333  else
334  {
335  return TRUE;
336  }
337  }
338 
347  function isKeywordMatching($answertext, $a_keyword)
348  {
349  $result = FALSE;
350  $textrating = $this->getTextRating();
351  include_once "./Services/Utilities/classes/class.ilStr.php";
352  switch ($textrating)
353  {
355  if (ilStr::strPos(ilStr::strToLower($answertext), ilStr::strToLower($a_keyword)) !== false) return TRUE;
356  break;
358  if (ilStr::strPos($answertext, $a_keyword) !== false) return TRUE;
359  break;
360  }
361  $answerwords = array();
362  if (preg_match_all("/([^\s.]+)/", $answertext, $matches))
363  {
364  foreach ($matches[1] as $answerword)
365  {
366  array_push($answerwords, trim($answerword));
367  }
368  }
369  foreach ($answerwords as $a_original)
370  {
371  switch ($textrating)
372  {
374  if (levenshtein($a_original, $a_keyword) <= 1) return TRUE;
375  break;
377  if (levenshtein($a_original, $a_keyword) <= 2) return TRUE;
378  break;
380  if (levenshtein($a_original, $a_keyword) <= 3) return TRUE;
381  break;
383  if (levenshtein($a_original, $a_keyword) <= 4) return TRUE;
384  break;
386  if (levenshtein($a_original, $a_keyword) <= 5) return TRUE;
387  break;
388  }
389  }
390  return $result;
391  }
392 
402  function calculateReachedPoints($active_id, $pass = NULL)
403  {
404  global $ilDB;
405 
406  $points = 0;
407  if (is_null($pass))
408  {
409  $pass = $this->getSolutionMaxPass($active_id);
410  }
411  $result = $ilDB->queryF("SELECT * FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
412  array('integer','integer','integer'),
413  array($active_id, $this->getId(), $pass)
414  );
415  if ($result->numRows() == 1)
416  {
417  $row = $ilDB->fetchAssoc($result);
418  if ($row["points"])
419  {
420  $points = $row["points"];
421  }
422  else
423  {
424  $keywords =& $this->getKeywordList();
425  if (count($keywords))
426  {
427  $foundkeyword = false;
428  foreach ($keywords as $keyword)
429  {
430  if (!$foundkeyword)
431  {
432  if ($this->isKeywordMatching($row["value1"], $keyword))
433  {
434  $foundkeyword = true;
435  }
436  }
437  }
438  if ($foundkeyword) $points = $this->getMaximumPoints();
439  }
440  }
441  }
442 
443  $points = parent::calculateReachedPoints($active_id, $pass = NULL, $points);
444  return $points;
445  }
446 
455  function saveWorkingData($active_id, $pass = NULL)
456  {
457  global $ilDB;
458  global $ilUser;
459 
460  include_once "./Services/Utilities/classes/class.ilStr.php";
461  if (is_null($pass))
462  {
463  include_once "./Modules/Test/classes/class.ilObjTest.php";
464  $pass = ilObjTest::_getPass($active_id);
465  }
466  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
467  array('integer','integer','integer'),
468  array($active_id, $this->getId(), $pass)
469  );
470  $text = ilUtil::stripSlashes($_POST["TEXT"], FALSE);
471  if ($this->getMaxNumOfChars())
472  {
473  include_once "./Services/Utilities/classes/class.ilStr.php";
474  $text_without_tags = preg_replace("/<[^>*?]>/is", "", $text);
475  $len_with_tags = ilStr::strLen($text);
476  $len_without_tags = ilStr::strLen($text_without_tags);
477  if ($this->getMaxNumOfChars() < $len_without_tags)
478  {
479  if (!$this->isHTML($text))
480  {
481  $text = ilStr::subStr($text, 0, $this->getMaxNumOfChars());
482  }
483  }
484  }
485  if ($this->isHTML($text))
486  {
487  $text = preg_replace("/<[^>]*$/ims", "", $text);
488  }
489  else
490  {
491  //$text = htmlentities($text, ENT_QUOTES, "UTF-8");
492  }
493  $entered_values = 0;
494  if (strlen($text))
495  {
496  $next_id = $ilDB->nextId('tst_solutions');
497  $affectedRows = $ilDB->insert("tst_solutions", array(
498  "solution_id" => array("integer", $next_id),
499  "active_fi" => array("integer", $active_id),
500  "question_fi" => array("integer", $this->getId()),
501  "value1" => array("clob", trim($text)),
502  "value2" => array("clob", null),
503  "pass" => array("integer", $pass),
504  "tstamp" => array("integer", time())
505  ));
506  $entered_values++;
507  }
508  if ($entered_values)
509  {
510  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
512  {
513  $this->logAction($this->lng->txtlng("assessment", "log_user_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
514  }
515  }
516  else
517  {
518  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
520  {
521  $this->logAction($this->lng->txtlng("assessment", "log_user_not_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
522  }
523  }
524  parent::saveWorkingData($active_id, $pass);
525  return true;
526  }
527 
528  function createRandomSolution($test_id, $user_id)
529  {
530  }
531 
538  function getQuestionType()
539  {
540  return "assTextQuestion";
541  }
542 
549  function getKeywords()
550  {
551  return $this->keywords;
552  }
553 
560  function setKeywords($a_keywords)
561  {
562  $this->keywords = $a_keywords;
563  }
564 
571  function &getKeywordList()
572  {
573  $keywords = array();
574  if (preg_match_all("/([^\s]+)/", $this->keywords, $matches))
575  {
576  foreach ($matches[1] as $keyword)
577  {
578  array_push($keywords, trim($keyword));
579  }
580  }
581  return $keywords;
582  }
583 
591  function getTextRating()
592  {
593  return $this->text_rating;
594  }
595 
603  function setTextRating($a_text_rating)
604  {
605  switch ($a_text_rating)
606  {
614  $this->text_rating = $a_text_rating;
615  break;
616  default:
617  $this->text_rating = TEXTGAP_RATING_CASEINSENSITIVE;
618  break;
619  }
620  }
621 
629  {
630  return "qpl_qst_essay";
631  }
632 
638  {
640  }
641 
654  public function setExportDetailsXLS(&$worksheet, $startrow, $active_id, $pass, &$format_title, &$format_bold)
655  {
656  include_once ("./Services/Excel/classes/class.ilExcelUtils.php");
657  $solutions = $this->getSolutionValues($active_id, $pass);
658  $worksheet->writeString($startrow, 0, ilExcelUtils::_convert_text($this->lng->txt($this->getQuestionType())), $format_title);
659  $worksheet->writeString($startrow, 1, ilExcelUtils::_convert_text($this->getTitle()), $format_title);
660  $i = 1;
661  $worksheet->writeString($startrow + $i, 0, ilExcelUtils::_convert_text($this->lng->txt("result")), $format_bold);
662  if (strlen($solutions[0]["value1"]))
663  {
664  $worksheet->write($startrow + $i, 1, ilExcelUtils::_convert_text($solutions[0]["value1"]));
665  }
666  $i++;
667  return $startrow + $i + 1;
668  }
669 
673  public function toJSON()
674  {
675  include_once("./Services/RTE/classes/class.ilRTE.php");
676  $result = array();
677  $result['id'] = (int) $this->getId();
678  $result['type'] = (string) $this->getQuestionType();
679  $result['title'] = (string) $this->getTitle();
680  $result['question'] = (string) ilRTE::_replaceMediaObjectImageSrc($this->getQuestion(), 0);
681  $result['nr_of_tries'] = (int) $this->getNrOfTries();
682  $result['shuffle'] = (bool) $this->getShuffle();
683  $result['maxlength'] = (int) $this->getMaxNumOfChars();
684  return json_encode($result);
685  }
686 
687 }
688 
689 ?>