ILIAS  release_6 Revision v6.24-5-g0c8bfefb3b8
class.assTextQuestion.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
3 
4 require_once './Modules/TestQuestionPool/classes/class.assQuestion.php';
5 require_once './Modules/Test/classes/inc.AssessmentConstants.php';
6 require_once './Modules/TestQuestionPool/interfaces/interface.ilObjQuestionScoringAdjustable.php';
7 require_once './Modules/TestQuestionPool/interfaces/interface.ilObjAnswerScoringAdjustable.php';
8 
23 {
32 
37 
46  public $keywords;
47 
48  public $answers;
49 
55  public $text_rating;
56 
57  /* method for automatic string matching */
58  private $matchcondition;
59 
60  public $keyword_relation = 'any';
61 
74  public function __construct(
75  $title = "",
76  $comment = "",
77  $author = "",
78  $owner = -1,
79  $question = ""
80  ) {
82  $this->wordCounterEnabled = false;
83  $this->maxNumOfChars = 0;
84  $this->points = 1;
85  $this->answers = array();
86  $this->matchcondition = 0;
87  }
88 
94  public function isComplete()
95  {
96  if (strlen($this->title)
97  && $this->author
98  && $this->question
99  && $this->getMaximumPoints() > 0
100  ) {
101  return true;
102  }
103  return false;
104  }
105 
111  public function saveToDb($original_id = "")
112  {
116  parent::saveToDb($original_id);
117  }
118 
126  public function loadFromDb($question_id)
127  {
128  global $DIC;
129  $ilDB = $DIC['ilDB'];
130 
131  $result = $ilDB->queryF(
132  "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",
133  array("integer"),
134  array($question_id)
135  );
136  if ($ilDB->numRows($result) == 1) {
137  $data = $ilDB->fetchAssoc($result);
138  $this->setId($question_id);
139  $this->setObjId($data["obj_fi"]);
140  $this->setTitle($data["title"]);
141  $this->setComment($data["description"]);
142  $this->setOriginalId($data["original_id"]);
143  $this->setNrOfTries($data['nr_of_tries']);
144  $this->setAuthor($data["author"]);
145  $this->setPoints((float) $data["points"]);
146  $this->setOwner($data["owner"]);
147  include_once("./Services/RTE/classes/class.ilRTE.php");
148  $this->setQuestion(ilRTE::_replaceMediaObjectImageSrc($data["question_text"], 1));
149  $this->setShuffle($data["shuffle"]);
150  $this->setWordCounterEnabled((bool) $data['word_cnt_enabled']);
151  $this->setMaxNumOfChars($data["maxnumofchars"]);
152  $this->setTextRating($this->isValidTextRating($data["textgap_rating"]) ? $data["textgap_rating"] : TEXTGAP_RATING_CASEINSENSITIVE);
153  $this->matchcondition = (strlen($data['matchcondition'])) ? $data['matchcondition'] : 0;
154  $this->setEstimatedWorkingTime(substr($data["working_time"], 0, 2), substr($data["working_time"], 3, 2), substr($data["working_time"], 6, 2));
155  $this->setKeywordRelation(($data['keyword_relation']));
156 
157  try {
158  $this->setLifecycle(ilAssQuestionLifecycle::getInstance($data['lifecycle']));
161  }
162 
163  try {
164  $this->setAdditionalContentEditingMode($data['add_cont_edit_mode']);
165  } catch (ilTestQuestionPoolException $e) {
166  }
167  }
168 
169  $result = $ilDB->queryF(
170  "SELECT * FROM qpl_a_essay WHERE question_fi = %s",
171  array("integer"),
172  array($this->getId())
173  );
174 
175  $this->flushAnswers();
176  while ($row = $ilDB->fetchAssoc($result)) {
177  $this->addAnswer($row['answertext'], $row['points']);
178  }
179 
180  parent::loadFromDb($question_id);
181  }
182 
188  public function duplicate($for_test = true, $title = "", $author = "", $owner = "", $testObjId = null)
189  {
190  if ($this->id <= 0) {
191  // The question has not been saved. It cannot be duplicated
192  return;
193  }
194  // duplicate the question in database
195  $this_id = $this->getId();
196  $thisObjId = $this->getObjId();
197 
198  $clone = $this;
199  include_once("./Modules/TestQuestionPool/classes/class.assQuestion.php");
201  $clone->id = -1;
202 
203  if ((int) $testObjId > 0) {
204  $clone->setObjId($testObjId);
205  }
206 
207  if ($title) {
208  $clone->setTitle($title);
209  }
210 
211  if ($author) {
212  $clone->setAuthor($author);
213  }
214  if ($owner) {
215  $clone->setOwner($owner);
216  }
217 
218  if ($for_test) {
219  $clone->saveToDb($original_id);
220  } else {
221  $clone->saveToDb();
222  }
223 
224  // copy question page content
225  $clone->copyPageOfQuestion($this_id);
226  // copy XHTML media objects
227  $clone->copyXHTMLMediaObjectsOfQuestion($this_id);
228  #$clone->duplicateAnswers($this_id);
229 
230  $clone->onDuplicate($thisObjId, $this_id, $clone->getObjId(), $clone->getId());
231 
232  return $clone->id;
233  }
234 
240  public function copyObject($target_questionpool_id, $title = "")
241  {
242  if ($this->id <= 0) {
243  // The question has not been saved. It cannot be duplicated
244  return;
245  }
246  // duplicate the question in database
247  $clone = $this;
248  include_once("./Modules/TestQuestionPool/classes/class.assQuestion.php");
250  $clone->id = -1;
251  $source_questionpool_id = $this->getObjId();
252  $clone->setObjId($target_questionpool_id);
253  if ($title) {
254  $clone->setTitle($title);
255  }
256  $clone->saveToDb();
257  // copy question page content
258  $clone->copyPageOfQuestion($original_id);
259  // copy XHTML media objects
260  $clone->copyXHTMLMediaObjectsOfQuestion($original_id);
261  // duplicate answers
262  #$clone->duplicateAnswers($original_id);
263 
264  $clone->onCopy($source_questionpool_id, $original_id, $clone->getObjId(), $clone->getId());
265 
266  return $clone->id;
267  }
268 
269  public function createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle = "")
270  {
271  if ($this->id <= 0) {
272  // The question has not been saved. It cannot be duplicated
273  return;
274  }
275 
276  include_once("./Modules/TestQuestionPool/classes/class.assQuestion.php");
277 
278  $sourceQuestionId = $this->id;
279  $sourceParentId = $this->getObjId();
280 
281  // duplicate the question in database
282  $clone = $this;
283  $clone->id = -1;
284 
285  $clone->setObjId($targetParentId);
286 
287  if ($targetQuestionTitle) {
288  $clone->setTitle($targetQuestionTitle);
289  }
290 
291  $clone->saveToDb();
292  // copy question page content
293  $clone->copyPageOfQuestion($sourceQuestionId);
294  // copy XHTML media objects
295  $clone->copyXHTMLMediaObjectsOfQuestion($sourceQuestionId);
296  // duplicate answers
297  #$clone->duplicateAnswers($sourceQuestionId);
298 
299  $clone->onCopy($sourceParentId, $sourceQuestionId, $clone->getObjId(), $clone->getId());
300 
301  return $clone->id;
302  }
303 
311  public function getMaxNumOfChars()
312  {
313  if (strcmp($this->maxNumOfChars, "") == 0) {
314  return 0;
315  } else {
316  return $this->maxNumOfChars;
317  }
318  }
319 
327  public function setMaxNumOfChars($maxchars = 0)
328  {
329  $this->maxNumOfChars = $maxchars;
330  }
331 
335  public function isWordCounterEnabled()
336  {
338  }
339 
344  {
345  $this->wordCounterEnabled = $wordCounterEnabled;
346  }
347 
354  public function getMaximumPoints()
355  {
356  if (in_array($this->getKeywordRelation(), self::getScoringModesWithPointsByQuestion())) {
357  return parent::getPoints();
358  }
359 
360  $points = 0;
361 
362  foreach ($this->answers as $answer) {
363  if ($answer->getPoints() > 0) {
364  $points = $points + $answer->getPoints();
365  }
366  }
367 
368  return $points;
369  }
370 
371  public function getMinimumPoints()
372  {
373  if (in_array($this->getKeywordRelation(), self::getScoringModesWithPointsByQuestion())) {
374  return 0;
375  }
376 
377  $points = 0;
378 
379  foreach ($this->answers as $answer) {
380  if ($answer->getPoints() < 0) {
381  $points = $points + $answer->getPoints();
382  }
383  }
384 
385  return $points;
386  }
396  public function setReachedPoints($active_id, $points, $pass = null)
397  {
398  global $DIC;
399  $ilDB = $DIC['ilDB'];
400 
401  if (($points > 0) && ($points <= $this->getPoints())) {
402  if (is_null($pass)) {
403  $pass = $this->getSolutionMaxPass($active_id);
404  }
405  $affectedRows = $ilDB->manipulateF(
406  "UPDATE tst_test_result SET points = %s WHERE active_fi = %s AND question_fi = %s AND pass = %s",
407  array('float','integer','integer','integer'),
408  array($points, $active_id, $this->getId(), $pass)
409  );
410  self::_updateTestPassResults($active_id, $pass);
411  return true;
412  } else {
413  return true;
414  }
415  }
416 
417  private function isValidTextRating($textRating)
418  {
419  switch ($textRating) {
427  return true;
428  }
429 
430  return false;
431  }
432 
441  public function isKeywordMatching($answertext, $a_keyword)
442  {
443  $result = false;
444  $textrating = $this->getTextRating();
445  include_once "./Services/Utilities/classes/class.ilStr.php";
446  switch ($textrating) {
448  if (ilStr::strPos(ilStr::strToLower($answertext), ilStr::strToLower($a_keyword)) !== false) {
449  return true;
450  }
451  break;
453  if (ilStr::strPos($answertext, $a_keyword) !== false) {
454  return true;
455  }
456  break;
457  }
458 
459  // "<p>red</p>" would not match "red" even with distance of 5
460  $answertext = strip_tags($answertext);
461 
462  $answerwords = array();
463  if (preg_match_all("/([^\s.]+)/", $answertext, $matches)) {
464  foreach ($matches[1] as $answerword) {
465  array_push($answerwords, trim($answerword));
466  }
467  }
468  foreach ($answerwords as $a_original) {
469  switch ($textrating) {
471  if (levenshtein($a_original, $a_keyword) <= 1) {
472  return true;
473  }
474  break;
476  if (levenshtein($a_original, $a_keyword) <= 2) {
477  return true;
478  }
479  break;
481  if (levenshtein($a_original, $a_keyword) <= 3) {
482  return true;
483  }
484  break;
486  if (levenshtein($a_original, $a_keyword) <= 4) {
487  return true;
488  }
489  break;
491  if (levenshtein($a_original, $a_keyword) <= 5) {
492  return true;
493  }
494  break;
495  }
496  }
497  return $result;
498  }
499 
500  protected function calculateReachedPointsForSolution($solution)
501  {
502  // Return min points when keyword relation is NON KEYWORDS
503  if ($this->getKeywordRelation() == 'non') {
504  return $this->getMinimumPoints();
505  }
506 
507  // Return min points if there are no answers present.
508  $answers = $this->getAnswers();
509 
510  if (count($answers) == 0) {
511  return $this->getMinimumPoints();
512  }
513 
514  switch ($this->getKeywordRelation()) {
515  case 'any':
516 
517  $points = 0;
518 
519  foreach ($answers as $answer) {
520  $qst_answer = $answer->getAnswertext();
521  $user_answer = ' ' . $solution;
522 
523  if ($this->isKeywordMatching($user_answer, $qst_answer)) {
524  $points += $answer->getPoints();
525  }
526  }
527 
528  break;
529 
530  case 'all':
531 
532  $points = $this->getMaximumPoints();
533 
534  foreach ($answers as $answer) {
535  $qst_answer = $answer->getAnswertext();
536  $user_answer = ' ' . $solution;
537 
538  if (!$this->isKeywordMatching($user_answer, $qst_answer)) {
539  $points = 0;
540  break;
541  }
542  }
543 
544  break;
545 
546  case 'one':
547 
548  $points = 0;
549 
550  foreach ($answers as $answer) {
551  $qst_answer = $answer->getAnswertext();
552  $user_answer = ' ' . $solution;
553 
554  if ($this->isKeywordMatching($user_answer, $qst_answer)) {
555  $points = $this->getMaximumPoints();
556  break;
557  }
558  }
559 
560  break;
561  }
562 
563  return $points;
564  }
565 
576  public function calculateReachedPoints($active_id, $pass = null, $authorizedSolution = true, $returndetails = false)
577  {
578  if ($returndetails) {
579  throw new ilTestException('return details not implemented for ' . __METHOD__);
580  }
581 
582  global $DIC;
583  $ilDB = $DIC['ilDB'];
584 
585  $points = 0;
586  if (is_null($pass)) {
587  $pass = $this->getSolutionMaxPass($active_id);
588  }
589 
590  $result = $this->getCurrentSolutionResultSet($active_id, $pass, $authorizedSolution);
591 
592  // Return min points when no answer was given.
593  if ($ilDB->numRows($result) == 0) {
594  return $this->getMinimumPoints();
595  }
596 
597  // Return points of points are already on the row.
598  $row = $ilDB->fetchAssoc($result);
599  if ($row["points"] != null) {
600  return $row["points"];
601  }
602 
603  return $this->calculateReachedPointsForSolution($row['value1']);
604  }
605 
614  public function saveWorkingData($active_id, $pass = null, $authorized = true)
615  {
616  global $DIC;
617  $ilDB = $DIC['ilDB'];
618  $ilUser = $DIC['ilUser'];
619 
620  include_once "./Services/Utilities/classes/class.ilStr.php";
621  if (is_null($pass)) {
622  include_once "./Modules/Test/classes/class.ilObjTest.php";
623  $pass = ilObjTest::_getPass($active_id);
624  }
625 
626  $entered_values = 0;
627  $text = $this->getSolutionSubmit();
628 
629  $this->getProcessLocker()->executeUserSolutionUpdateLockOperation(function () use (&$entered_values, $active_id, $pass, $authorized, $text) {
630  $this->removeCurrentSolution($active_id, $pass, $authorized);
631 
632  if (strlen($text)) {
633  $this->saveCurrentSolution($active_id, $pass, trim($text), null, $authorized);
634  $entered_values++;
635  }
636  });
637 
638  if ($entered_values) {
639  include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
641  assQuestion::logAction($this->lng->txtlng("assessment", "log_user_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
642  }
643  } else {
644  include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
646  assQuestion::logAction($this->lng->txtlng("assessment", "log_user_not_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
647  }
648  }
649 
650  return true;
651  }
652 
656  public function getSolutionSubmit()
657  {
658  $text = ilUtil::stripSlashes($_POST["TEXT"], false);
659 
660  if (ilUtil::isHTML($text)) {
661  $text = $this->getHtmlUserSolutionPurifier()->purify($text);
662  }
663 
664  return $text;
665  }
666 
667  public function saveAdditionalQuestionDataToDb()
668  {
670  global $DIC;
671  $ilDB = $DIC['ilDB'];
672  $ilDB->manipulateF(
673  "DELETE FROM " . $this->getAdditionalTableName() . " WHERE question_fi = %s",
674  array( "integer" ),
675  array( $this->getId()
676  )
677  );
678 
679  $fields = array(
680  'question_fi' => array('integer', $this->getId()),
681  'maxnumofchars' => array('integer', $this->getMaxNumOfChars()),
682  'word_cnt_enabled' => array('integer', (int) $this->isWordCounterEnabled()),
683  'keywords' => array('text', null),
684  'textgap_rating' => array('text', $this->getTextRating()),
685  'matchcondition' => array('integer', $this->matchcondition),
686  'keyword_relation' => array('text', $this->getKeywordRelation())
687  );
688 
689  $ilDB->insert($this->getAdditionalTableName(), $fields);
690  }
691 
692  public function saveAnswerSpecificDataToDb()
693  {
695  global $DIC;
696  $ilDB = $DIC['ilDB'];
697 
698  $ilDB->manipulateF(
699  "DELETE FROM qpl_a_essay WHERE question_fi = %s",
700  array( "integer" ),
701  array( $this->getId() )
702  );
703 
704  foreach ($this->answers as $answer) {
706  $nextID = $ilDB->nextId('qpl_a_essay');
707  $ilDB->manipulateF(
708  "INSERT INTO qpl_a_essay (answer_id, question_fi, answertext, points) VALUES (%s, %s, %s, %s)",
709  array( "integer", "integer", "text", 'float' ),
710  array(
711  $nextID,
712  $this->getId(),
713  $answer->getAnswertext(),
714  $answer->getPoints()
715  )
716  );
717  }
718  }
719 
726  public function getQuestionType()
727  {
728  return "assTextQuestion";
729  }
730 
738  public function getTextRating()
739  {
740  return $this->text_rating;
741  }
742 
750  public function setTextRating($a_text_rating)
751  {
752  switch ($a_text_rating) {
760  $this->text_rating = $a_text_rating;
761  break;
762  default:
763  $this->text_rating = TEXTGAP_RATING_CASEINSENSITIVE;
764  break;
765  }
766  }
767 
774  public function getAdditionalTableName()
775  {
776  return "qpl_qst_essay";
777  }
778 
783  public function getRTETextWithMediaObjects()
784  {
785  return parent::getRTETextWithMediaObjects();
786  }
787 
791  public function setExportDetailsXLS($worksheet, $startrow, $active_id, $pass)
792  {
793  parent::setExportDetailsXLS($worksheet, $startrow, $active_id, $pass);
794 
795  $solutions = $this->getSolutionValues($active_id, $pass);
796 
797  $i = 1;
798  $worksheet->setCell($startrow + $i, 0, $this->lng->txt("result"));
799  $worksheet->setBold($worksheet->getColumnCoord(0) . ($startrow + $i));
800 
801  require_once 'Modules/Test/classes/class.ilObjAssessmentFolder.php';
802  $assessment_folder = new ilObjAssessmentFolder();
803 
804  $string_escaping_org_value = $worksheet->getStringEscaping();
805  if ($assessment_folder->getExportEssayQuestionsWithHtml() == 1) {
806  $worksheet->setStringEscaping(false);
807  }
808 
809  if (strlen($solutions[0]["value1"])) {
810  $worksheet->setCell($startrow + $i, 1, $solutions[0]["value1"]);
811  }
812  $i++;
813 
814  $worksheet->setStringEscaping($string_escaping_org_value);
815  return $startrow + $i + 1;
816  }
817 
821  public function toJSON()
822  {
823  include_once("./Services/RTE/classes/class.ilRTE.php");
824  $result = array();
825  $result['id'] = (int) $this->getId();
826  $result['type'] = (string) $this->getQuestionType();
827  $result['title'] = (string) $this->getTitle();
828  $result['question'] = $this->formatSAQuestion($this->getQuestion());
829  $result['nr_of_tries'] = (int) $this->getNrOfTries();
830  $result['shuffle'] = (bool) $this->getShuffle();
831  $result['maxlength'] = (int) $this->getMaxNumOfChars();
832  return json_encode($result);
833  }
834 
835  public function getAnswerCount()
836  {
837  return count($this->answers);
838  }
839 
853  public function addAnswer(
854  $answertext = "",
855  $points = 0.0,
856  $points_unchecked = 0.0,
857  $order = 0,
858  $answerimage = ""
859  ) {
860  include_once "./Modules/TestQuestionPool/classes/class.assAnswerMultipleResponseImage.php";
861 
862  // add answer
863  $answer = new ASS_AnswerMultipleResponseImage($answertext, $points);
864  $this->answers[] = $answer;
865  }
866 
867  public function getAnswers()
868  {
869  return $this->answers;
870  }
871 
881  public function getAnswer($index = 0)
882  {
883  if ($index < 0) {
884  return null;
885  }
886  if (count($this->answers) < 1) {
887  return null;
888  }
889  if ($index >= count($this->answers)) {
890  return null;
891  }
892 
893  return $this->answers[$index];
894  }
895 
904  public function deleteAnswer($index = 0)
905  {
906  if ($index < 0) {
907  return;
908  }
909  if (count($this->answers) < 1) {
910  return;
911  }
912  if ($index >= count($this->answers)) {
913  return;
914  }
915  $answer = $this->answers[$index];
916  if (strlen($answer->getImage())) {
917  $this->deleteImage($answer->getImage());
918  }
919  unset($this->answers[$index]);
920  $this->answers = array_values($this->answers);
921  for ($i = 0; $i < count($this->answers); $i++) {
922  if ($this->answers[$i]->getOrder() > $index) {
923  $this->answers[$i]->setOrder($i);
924  }
925  }
926  }
927 
928  public function getAnswerTableName()
929  {
930  return 'qpl_a_essay';
931  }
932 
939  public function flushAnswers()
940  {
941  $this->answers = array();
942  }
943 
944  public function setAnswers($answers)
945  {
946  if (isset($answers['answer'])) {
947  $count = count($answers['answer']);
948  $withPoints = true;
949  } else {
950  $count = count($answers);
951  $withPoints = false;
952  }
953 
954  $this->flushAnswers();
955 
956  for ($i = 0; $i < $count; $i++) {
957  if ($withPoints) {
958  $this->addAnswer($answers['answer'][$i], $answers['points'][$i]);
959  } else {
960  $this->addAnswer($answers[$i], 0);
961  }
962  }
963  }
964 
966  {
967  global $DIC;
968  $ilDB = $DIC['ilDB'];
969 
970  $result = $ilDB->queryF(
971  "SELECT * FROM qpl_a_essay WHERE question_fi = %s",
972  array('integer'),
973  array($original_id)
974  );
975  if ($result->numRows()) {
976  while ($row = $ilDB->fetchAssoc($result)) {
977  $next_id = $ilDB->nextId('qpl_a_essay');
978  $affectedRows = $ilDB->manipulateF(
979  "INSERT INTO qpl_a_essay (answer_id, question_fi, answertext, points)
980  VALUES (%s, %s, %s, %s)",
981  array('integer','integer','text','float'),
982  array($next_id, $this->getId(), $row["answertext"], $row["points"])
983  );
984  }
985  }
986  }
987 
988  public function getKeywordRelation()
989  {
991  }
992 
997  public function setKeywordRelation($a_relation)
998  {
999  $this->keyword_relation = $a_relation;
1000  }
1001 
1002  public static function getValidScoringModes()
1003  {
1004  return array_merge(self::getScoringModesWithPointsByQuestion(), self::getScoringModesWithPointsByKeyword());
1005  }
1006 
1007  public static function getScoringModesWithPointsByQuestion()
1008  {
1009  return array('non', 'all', 'one');
1010  }
1011 
1012  public static function getScoringModesWithPointsByKeyword()
1013  {
1014  return array('any');
1015  }
1016 
1017 
1028  public function isAnswered($active_id, $pass = null)
1029  {
1030  $numExistingSolutionRecords = assQuestion::getNumExistingSolutionRecords($active_id, $pass, $this->getId());
1031 
1032  return $numExistingSolutionRecords > 0;
1033  }
1034 
1045  public static function isObligationPossible($questionId)
1046  {
1047  return true;
1048  }
1049 
1050  public function countLetters($text)
1051  {
1052  $text = strip_tags($text);
1053 
1054  $text = str_replace('&gt;', '>', $text);
1055  $text = str_replace('&lt;', '<', $text);
1056  $text = str_replace('&nbsp;', ' ', $text);
1057  $text = str_replace('&amp;', '&', $text);
1058 
1059  $text = str_replace("\r\n", "\n", $text);
1060  $text = str_replace("\n", "", $text);
1061 
1062  return ilStr::strLen($text);
1063  }
1064 
1065  public function countWords($text)
1066  {
1067  $text = str_replace('&nbsp;', ' ', $text);
1068 
1069  $text = preg_replace('/[.,:;!?\-_#\'"+*\\/=()&%§$]/m', '', $text);
1070 
1071  $text = preg_replace('/^\s*/m', '', $text);
1072  $text = preg_replace('/\s*$/m', '', $text);
1073  $text = preg_replace('/\s+/m', ' ', $text);
1074 
1075  return count(explode(' ', $text));
1076  }
1077 
1078  public function getLatestAutosaveContent($active_id)
1079  {
1080  $question_fi = $this->getId();
1081 
1082  // Do we have an unauthorized result?
1083  $cntresult = $this->db->query('
1084  SELECT count(solution_id) cnt
1085  FROM tst_solutions
1086  WHERE active_fi = ' . $this->db->quote($active_id, 'int') . '
1087  AND question_fi = ' . $this->db->quote($this->getId(), 'int') . '
1088  AND authorized = ' . $this->db->quote(0, 'int')
1089  );
1090  $row = $this->db->fetchAssoc($cntresult);
1091  if($row['cnt'] > 0 ) {
1092  $tresult = $this->db->query('
1093  SELECT value1
1094  FROM tst_solutions
1095  WHERE active_fi = ' . $this->db->quote($active_id, 'int') . '
1096  AND question_fi = ' . $this->db->quote($this->getId(), 'int') . '
1097  AND authorized = ' . $this->db->quote(0, 'int')
1098  );
1099  $trow = $this->db->fetchAssoc($tresult);
1100  return $trow['value1'];
1101  }
1102  return '';
1103  }
1104 }
duplicate($for_test=true, $title="", $author="", $owner="", $testObjId=null)
Duplicates an assTextQuestion.
static logAction($logtext="", $active_id="", $question_id="")
Logs an action into the Test&Assessment log.
getId()
Gets the id of the assQuestion object.
setExportDetailsXLS($worksheet, $startrow, $active_id, $pass)
{}
static _getOriginalId($question_id)
Returns the original id of a question.
formatSAQuestion($a_q)
Format self assessment question.
const TEXTGAP_RATING_LEVENSHTEIN5
static strLen($a_string)
Definition: class.ilStr.php:78
static _getPass($active_id)
Retrieves the actual pass of a given user for a given test.
static getScoringModesWithPointsByKeyword()
static getNumExistingSolutionRecords($activeId, $pass, $questionId)
returns the number of existing solution records for the given test active / pass and given question i...
$data
Definition: storeScorm.php:23
static strPos($a_haystack, $a_needle, $a_offset=null)
Definition: class.ilStr.php:30
$result
isAnswered($active_id, $pass=null)
returns boolean wether the question is answered during test pass or not
saveAdditionalQuestionDataToDb()
Saves a record to the question types additional data table.
getPoints()
Returns the maximum available points for the question.
const TEXTGAP_RATING_LEVENSHTEIN2
const TEXTGAP_RATING_LEVENSHTEIN1
Abstract basic class which is to be extended by the concrete assessment question type classes...
isComplete()
Returns true, if a multiple choice question is complete for use.
createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle="")
ASS_AnswerBinaryStateImage is a class for answers with a binary state indicator (checked/unchecked, set/unset) and an image file.
getSolutionValues($active_id, $pass=null, $authorized=true)
Loads solutions of a given user from the database an returns it.
setId($id=-1)
Sets the id of the assQuestion object.
loadFromDb($question_id)
Loads a assTextQuestion object from a database.
saveToDb($original_id="")
Saves a assTextQuestion object to a database.
saveWorkingData($active_id, $pass=null, $authorized=true)
Saves the learners input of the question to the database.
copyObject($target_questionpool_id, $title="")
Copies an assTextQuestion object.
getSolutionMaxPass($active_id)
Returns the maximum pass a users question solution.
setEstimatedWorkingTime($hour=0, $min=0, $sec=0)
Sets the estimated working time of a question from given hour, minute and second. ...
static strToLower($a_string)
Definition: class.ilStr.php:87
toJSON()
Returns a JSON representation of the question.
setNrOfTries($a_nr_of_tries)
setAdditionalContentEditingMode($additinalContentEditingMode)
setter for additional content editing mode for this question
setShuffle($shuffle=true)
Sets the shuffle flag.
static _replaceMediaObjectImageSrc($a_text, $a_direction=0, $nic=IL_INST_ID)
Replaces image source from mob image urls with the mob id or replaces mob id with the correct image s...
getObjId()
Get the object id of the container object.
setWordCounterEnabled($wordCounterEnabled)
getShuffle()
Gets the shuffle flag.
Base Exception for all Exceptions relating to Modules/Test.
getMaximumPoints()
Returns the maximum points, a learner can reach answering the question.
$index
Definition: metadata.php:128
static _getLogLanguage()
retrieve the log language for assessment logging
__construct( $title="", $comment="", $author="", $owner=-1, $question="")
assTextQuestion constructor
setAuthor($author="")
Sets the authors name of the assQuestion object.
static _enabledAssessmentLogging()
check wether assessment logging is enabled or not
isValidTextRating($textRating)
const TEXTGAP_RATING_LEVENSHTEIN3
Class for text questions.
calculateReachedPointsForSolution($solution)
duplicateAnswers($original_id)
flushAnswers()
Deletes all answers.
saveCurrentSolution($active_id, $pass, $value1, $value2, $authorized=true, $tstamp=null)
Class ilObjAssessmentFolder.
static getScoringModesWithPointsByQuestion()
const TEXTGAP_RATING_CASESENSITIVE
setKeywordRelation($a_relation)
This method implements a default behaviour.
Interface ilObjAnswerScoringAdjustable.
setTextRating($a_text_rating)
Sets the rating option for text comparisons.
getQuestion()
Gets the question string of the question object.
$ilUser
Definition: imgupload.php:18
setMaxNumOfChars($maxchars=0)
Sets the maximum number of characters for the text solution.
getQuestionType()
Returns the question type of the question.
setReachedPoints($active_id, $points, $pass=null)
Sets the points, a learner has reached answering the question.
isKeywordMatching($answertext, $a_keyword)
Checks if one of the keywords matches the answertext.
getAdditionalTableName()
Returns the name of the additional question data table in the database.
static stripSlashes($a_str, $a_strip_html=true, $a_allow="")
strip slashes if magic qoutes is enabled
getAnswer($index=0)
Returns an answer with a given index.
deleteAnswer($index=0)
Deletes an answer with a given index.
saveAnswerSpecificDataToDb()
Saves the answer specific records into a question types answer table.
setPoints($a_points)
Sets the maximum available points for the question.
addAnswer( $answertext="", $points=0.0, $points_unchecked=0.0, $order=0, $answerimage="")
Adds a possible answer for a multiple choice question.
saveQuestionDataToDb($original_id="")
getMaxNumOfChars()
Gets the maximum number of characters for the text solution.
calculateReachedPoints($active_id, $pass=null, $authorizedSolution=true, $returndetails=false)
Returns the points, a learner has reached answering the question.
getRTETextWithMediaObjects()
Collects all text in the question which could contain media objects which were created with the Rich ...
setQuestion($question="")
Sets the question string of the question object.
Interface ilObjQuestionScoringAdjustable.
removeCurrentSolution($active_id, $pass, $authorized=true)
__construct(Container $dic, ilPlugin $plugin)
const TEXTGAP_RATING_LEVENSHTEIN4
global $ilDB
setOriginalId($original_id)
$DIC
Definition: xapitoken.php:46
getCurrentSolutionResultSet($active_id, $pass, $authorized=true)
Get a restulset for the current user solution for a this question by active_id and pass...
setLifecycle(ilAssQuestionLifecycle $lifecycle)
getTitle()
Gets the title string of the assQuestion object.
static isHTML($a_text)
Checks if a given string contains HTML or not.
getTextRating()
Returns the rating option for text comparisons.
setTitle($title="")
Sets the title string of the assQuestion object.
setObjId($obj_id=0)
Set the object id of the container object.
setComment($comment="")
Sets the comment string of the assQuestion object.
$_POST["username"]
getLatestAutosaveContent($active_id)
static isObligationPossible($questionId)
returns boolean wether it is possible to set this question type as obligatory or not considering the ...
$i
Definition: metadata.php:24
setOwner($owner="")
Sets the creator/owner ID of the assQuestion object.
const TEXTGAP_RATING_CASEINSENSITIVE