ILIAS  release_7 Revision v7.30-3-g800a261c036
All Data Structures Namespaces Files Functions Variables Modules Pages
class.assTextQuestion.php
Go to the documentation of this file.
1 <?php
2 
19 require_once './Modules/TestQuestionPool/classes/class.assQuestion.php';
20 require_once './Modules/Test/classes/inc.AssessmentConstants.php';
21 require_once './Modules/TestQuestionPool/interfaces/interface.ilObjQuestionScoringAdjustable.php';
22 require_once './Modules/TestQuestionPool/interfaces/interface.ilObjAnswerScoringAdjustable.php';
23 
38 {
47 
52 
61  public $keywords;
62 
63  public $answers;
64 
70  public $text_rating;
71 
72  /* method for automatic string matching */
73  private $matchcondition;
74 
75  public $keyword_relation = 'any';
76 
89  public function __construct(
90  $title = "",
91  $comment = "",
92  $author = "",
93  $owner = -1,
94  $question = ""
95  ) {
97  $this->wordCounterEnabled = false;
98  $this->maxNumOfChars = 0;
99  $this->points = 1;
100  $this->answers = array();
101  $this->matchcondition = 0;
102  }
103 
109  public function isComplete()
110  {
111  if (strlen($this->title)
112  && $this->author
113  && $this->question
114  && $this->getMaximumPoints() > 0
115  ) {
116  return true;
117  }
118  return false;
119  }
120 
126  public function saveToDb($original_id = "")
127  {
131  parent::saveToDb($original_id);
132  }
133 
141  public function loadFromDb($question_id)
142  {
143  global $DIC;
144  $ilDB = $DIC['ilDB'];
145 
146  $result = $ilDB->queryF(
147  "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",
148  array("integer"),
149  array($question_id)
150  );
151  if ($ilDB->numRows($result) == 1) {
152  $data = $ilDB->fetchAssoc($result);
153  $this->setId($question_id);
154  $this->setObjId($data["obj_fi"]);
155  $this->setTitle($data["title"]);
156  $this->setComment($data["description"]);
157  $this->setOriginalId($data["original_id"]);
158  $this->setNrOfTries($data['nr_of_tries']);
159  $this->setAuthor($data["author"]);
160  $this->setPoints((float) $data["points"]);
161  $this->setOwner($data["owner"]);
162  include_once("./Services/RTE/classes/class.ilRTE.php");
163  $this->setQuestion(ilRTE::_replaceMediaObjectImageSrc($data["question_text"], 1));
164  $this->setShuffle($data["shuffle"]);
165  $this->setWordCounterEnabled((bool) $data['word_cnt_enabled']);
166  $this->setMaxNumOfChars($data["maxnumofchars"]);
167  $this->setTextRating($this->isValidTextRating($data["textgap_rating"]) ? $data["textgap_rating"] : TEXTGAP_RATING_CASEINSENSITIVE);
168  $this->matchcondition = (strlen($data['matchcondition'])) ? $data['matchcondition'] : 0;
169  $this->setEstimatedWorkingTime(substr($data["working_time"], 0, 2), substr($data["working_time"], 3, 2), substr($data["working_time"], 6, 2));
170  $this->setKeywordRelation(($data['keyword_relation']));
171 
172  try {
173  $this->setLifecycle(ilAssQuestionLifecycle::getInstance($data['lifecycle']));
176  }
177 
178  try {
179  $this->setAdditionalContentEditingMode($data['add_cont_edit_mode']);
180  } catch (ilTestQuestionPoolException $e) {
181  }
182  }
183 
184  $result = $ilDB->queryF(
185  "SELECT * FROM qpl_a_essay WHERE question_fi = %s",
186  array("integer"),
187  array($this->getId())
188  );
189 
190  $this->flushAnswers();
191  while ($row = $ilDB->fetchAssoc($result)) {
192  $this->addAnswer($row['answertext'], $row['points']);
193  }
194 
195  parent::loadFromDb($question_id);
196  }
197 
203  public function duplicate($for_test = true, $title = "", $author = "", $owner = "", $testObjId = null)
204  {
205  if ($this->id <= 0) {
206  // The question has not been saved. It cannot be duplicated
207  return;
208  }
209  // duplicate the question in database
210  $this_id = $this->getId();
211  $thisObjId = $this->getObjId();
212 
213  $clone = $this;
214  include_once("./Modules/TestQuestionPool/classes/class.assQuestion.php");
216  $clone->id = -1;
217 
218  if ((int) $testObjId > 0) {
219  $clone->setObjId($testObjId);
220  }
221 
222  if ($title) {
223  $clone->setTitle($title);
224  }
225 
226  if ($author) {
227  $clone->setAuthor($author);
228  }
229  if ($owner) {
230  $clone->setOwner($owner);
231  }
232 
233  if ($for_test) {
234  $clone->saveToDb($original_id);
235  } else {
236  $clone->saveToDb();
237  }
238 
239  // copy question page content
240  $clone->copyPageOfQuestion($this_id);
241  // copy XHTML media objects
242  $clone->copyXHTMLMediaObjectsOfQuestion($this_id);
243  #$clone->duplicateAnswers($this_id);
244 
245  $clone->onDuplicate($thisObjId, $this_id, $clone->getObjId(), $clone->getId());
246 
247  return $clone->id;
248  }
249 
255  public function copyObject($target_questionpool_id, $title = "")
256  {
257  if ($this->id <= 0) {
258  // The question has not been saved. It cannot be duplicated
259  return;
260  }
261  // duplicate the question in database
262  $clone = $this;
263  include_once("./Modules/TestQuestionPool/classes/class.assQuestion.php");
265  $clone->id = -1;
266  $source_questionpool_id = $this->getObjId();
267  $clone->setObjId($target_questionpool_id);
268  if ($title) {
269  $clone->setTitle($title);
270  }
271  $clone->saveToDb();
272  // copy question page content
273  $clone->copyPageOfQuestion($original_id);
274  // copy XHTML media objects
275  $clone->copyXHTMLMediaObjectsOfQuestion($original_id);
276  // duplicate answers
277  #$clone->duplicateAnswers($original_id);
278 
279  $clone->onCopy($source_questionpool_id, $original_id, $clone->getObjId(), $clone->getId());
280 
281  return $clone->id;
282  }
283 
284  public function createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle = "")
285  {
286  if ($this->id <= 0) {
287  // The question has not been saved. It cannot be duplicated
288  return;
289  }
290 
291  include_once("./Modules/TestQuestionPool/classes/class.assQuestion.php");
292 
293  $sourceQuestionId = $this->id;
294  $sourceParentId = $this->getObjId();
295 
296  // duplicate the question in database
297  $clone = $this;
298  $clone->id = -1;
299 
300  $clone->setObjId($targetParentId);
301 
302  if ($targetQuestionTitle) {
303  $clone->setTitle($targetQuestionTitle);
304  }
305 
306  $clone->saveToDb();
307  // copy question page content
308  $clone->copyPageOfQuestion($sourceQuestionId);
309  // copy XHTML media objects
310  $clone->copyXHTMLMediaObjectsOfQuestion($sourceQuestionId);
311  // duplicate answers
312  #$clone->duplicateAnswers($sourceQuestionId);
313 
314  $clone->onCopy($sourceParentId, $sourceQuestionId, $clone->getObjId(), $clone->getId());
315 
316  return $clone->id;
317  }
318 
326  public function getMaxNumOfChars()
327  {
328  if (strcmp($this->maxNumOfChars, "") == 0) {
329  return 0;
330  } else {
331  return $this->maxNumOfChars;
332  }
333  }
334 
342  public function setMaxNumOfChars($maxchars = 0)
343  {
344  $this->maxNumOfChars = $maxchars;
345  }
346 
350  public function isWordCounterEnabled()
351  {
353  }
354 
359  {
360  $this->wordCounterEnabled = $wordCounterEnabled;
361  }
362 
369  public function getMaximumPoints()
370  {
371  if (in_array($this->getKeywordRelation(), self::getScoringModesWithPointsByQuestion())) {
372  return parent::getPoints();
373  }
374 
375  $points = 0;
376 
377  foreach ($this->answers as $answer) {
378  if ($answer->getPoints() > 0) {
379  $points = $points + $answer->getPoints();
380  }
381  }
382 
383  return $points;
384  }
385 
386  public function getMinimumPoints()
387  {
388  if (in_array($this->getKeywordRelation(), self::getScoringModesWithPointsByQuestion())) {
389  return 0;
390  }
391 
392  $points = 0;
393 
394  foreach ($this->answers as $answer) {
395  if ($answer->getPoints() < 0) {
396  $points = $points + $answer->getPoints();
397  }
398  }
399 
400  return $points;
401  }
411  public function setReachedPoints($active_id, $points, $pass = null)
412  {
413  global $DIC;
414  $ilDB = $DIC['ilDB'];
415 
416  if (($points > 0) && ($points <= $this->getPoints())) {
417  if (is_null($pass)) {
418  $pass = $this->getSolutionMaxPass($active_id);
419  }
420  $affectedRows = $ilDB->manipulateF(
421  "UPDATE tst_test_result SET points = %s WHERE active_fi = %s AND question_fi = %s AND pass = %s",
422  array('float','integer','integer','integer'),
423  array($points, $active_id, $this->getId(), $pass)
424  );
425  self::_updateTestPassResults($active_id, $pass);
426  return true;
427  } else {
428  return true;
429  }
430  }
431 
432  private function isValidTextRating($textRating)
433  {
434  switch ($textRating) {
442  return true;
443  }
444 
445  return false;
446  }
447 
456  public function isKeywordMatching($answertext, $a_keyword)
457  {
458  global $DIC;
459  $refinery = $DIC->refinery();
460  $result = false;
461  $textrating = $this->getTextRating();
462  include_once "./Services/Utilities/classes/class.ilStr.php";
463 
464  switch ($textrating) {
466  if (ilStr::strPos(ilStr::strToLower($answertext), ilStr::strToLower($a_keyword)) !== false) {
467  return true;
468  }
469  break;
471  if (ilStr::strPos($answertext, $a_keyword) !== false) {
472  return true;
473  }
474  break;
475  }
476 
477  // "<p>red</p>" would not match "red" even with distance of 5
478  $answertext = strip_tags($answertext);
479  $answerwords = array();
480  if (preg_match_all("/([^\s.]+)/", $answertext, $matches)) {
481  foreach ($matches[1] as $answerword) {
482  array_push($answerwords, trim($answerword));
483  }
484  }
485 
486  // create correct transformation
487  switch ($textrating) {
489  $transformation = $refinery->string()->levenshtein()->standard($a_keyword, 1);
490  break;
492  $transformation = $refinery->string()->levenshtein()->standard($a_keyword, 2);
493  break;
495  $transformation = $refinery->string()->levenshtein()->standard($a_keyword, 3);
496  break;
498  $transformation = $refinery->string()->levenshtein()->standard($a_keyword, 4);
499  break;
501  $transformation = $refinery->string()->levenshtein()->standard($a_keyword, 5);
502  break;
503  }
504 
505  // run answers against Levenshtein methods
506  foreach ($answerwords as $a_original) {
507  if (isset($transformation) && $transformation->transform($a_original) >= 0) {
508  return true;
509  }
510  }
511  return $result;
512  }
513 
514  protected function calculateReachedPointsForSolution($solution)
515  {
516  $solution = html_entity_decode($solution);
517  // Return min points when keyword relation is NON KEYWORDS
518  if ($this->getKeywordRelation() == 'non') {
519  return $this->getMinimumPoints();
520  }
521 
522  // Return min points if there are no answers present.
523  $answers = $this->getAnswers();
524 
525  if (count($answers) == 0) {
526  return $this->getMinimumPoints();
527  }
528 
529  switch ($this->getKeywordRelation()) {
530  case 'any':
531  $points = 0;
532  foreach ($answers as $answer) {
533  $qst_answer = $answer->getAnswertext();
534  $user_answer = ' ' . $solution;
535  if ($this->isKeywordMatching($user_answer, $qst_answer)) {
536  $points += $answer->getPoints();
537  }
538  }
539  break;
540 
541  case 'all':
542  $points = $this->getMaximumPoints();
543  foreach ($answers as $answer) {
544  $qst_answer = $answer->getAnswertext();
545  $user_answer = ' ' . $solution;
546  if (!$this->isKeywordMatching($user_answer, $qst_answer)) {
547  $points = 0;
548  break;
549  }
550  }
551  break;
552 
553  case 'one':
554  $points = 0;
555  foreach ($answers as $answer) {
556  $qst_answer = $answer->getAnswertext();
557  $user_answer = ' ' . $solution;
558  if ($this->isKeywordMatching($user_answer, $qst_answer)) {
559  $points = $this->getMaximumPoints();
560  break;
561  }
562  }
563  break;
564  }
565 
566  return $points;
567  }
568 
579  public function calculateReachedPoints($active_id, $pass = null, $authorizedSolution = true, $returndetails = false)
580  {
581  if ($returndetails) {
582  throw new ilTestException('return details not implemented for ' . __METHOD__);
583  }
584 
585  global $DIC;
586  $ilDB = $DIC['ilDB'];
587 
588  $points = 0;
589  if (is_null($pass)) {
590  $pass = $this->getSolutionMaxPass($active_id);
591  }
592 
593  $result = $this->getCurrentSolutionResultSet($active_id, $pass, $authorizedSolution);
594 
595  // Return min points when no answer was given.
596  if ($ilDB->numRows($result) == 0) {
597  return $this->getMinimumPoints();
598  }
599 
600  // Return points of points are already on the row.
601  $row = $ilDB->fetchAssoc($result);
602  if ($row["points"] != null) {
603  return $row["points"];
604  }
605 
606  return $this->calculateReachedPointsForSolution($row['value1']);
607  }
608 
617  public function saveWorkingData($active_id, $pass = null, $authorized = true)
618  {
619  global $DIC;
620  $ilDB = $DIC['ilDB'];
621  $ilUser = $DIC['ilUser'];
622 
623  include_once "./Services/Utilities/classes/class.ilStr.php";
624  if (is_null($pass)) {
625  include_once "./Modules/Test/classes/class.ilObjTest.php";
626  $pass = ilObjTest::_getPass($active_id);
627  }
628 
629  $entered_values = 0;
630  $text = $this->getSolutionSubmit();
631 
632  $this->getProcessLocker()->executeUserSolutionUpdateLockOperation(function () use (&$entered_values, $active_id, $pass, $authorized, $text) {
633  $this->removeCurrentSolution($active_id, $pass, $authorized);
634 
635  if (strlen($text)) {
636  $this->saveCurrentSolution($active_id, $pass, trim($text), null, $authorized);
637  $entered_values++;
638  }
639  });
640 
641  if ($entered_values) {
642  include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
644  assQuestion::logAction($this->lng->txtlng("assessment", "log_user_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
645  }
646  } else {
647  include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
649  assQuestion::logAction($this->lng->txtlng("assessment", "log_user_not_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
650  }
651  }
652 
653  return true;
654  }
655 
659  public function getSolutionSubmit()
660  {
661  if (ilObjAdvancedEditing::_getRichTextEditor() === 'tinymce') {
662  $text = ilUtil::stripSlashes($_POST["TEXT"], false);
663  } else {
664  $text = htmlentities($_POST["TEXT"]);
665  }
666 
667  if (ilUtil::isHTML($text)) {
668  $text = $this->getHtmlUserSolutionPurifier()->purify($text);
669  }
670 
671  return $text;
672  }
673 
674  public function saveAdditionalQuestionDataToDb()
675  {
677  global $DIC;
678  $ilDB = $DIC['ilDB'];
679  $ilDB->manipulateF(
680  "DELETE FROM " . $this->getAdditionalTableName() . " WHERE question_fi = %s",
681  array( "integer" ),
682  array( $this->getId()
683  )
684  );
685 
686  $fields = array(
687  'question_fi' => array('integer', $this->getId()),
688  'maxnumofchars' => array('integer', $this->getMaxNumOfChars()),
689  'word_cnt_enabled' => array('integer', (int) $this->isWordCounterEnabled()),
690  'keywords' => array('text', null),
691  'textgap_rating' => array('text', $this->getTextRating()),
692  'matchcondition' => array('integer', $this->matchcondition),
693  'keyword_relation' => array('text', $this->getKeywordRelation())
694  );
695 
696  $ilDB->insert($this->getAdditionalTableName(), $fields);
697  }
698 
699  public function saveAnswerSpecificDataToDb()
700  {
702  global $DIC;
703  $ilDB = $DIC['ilDB'];
704 
705  $ilDB->manipulateF(
706  "DELETE FROM qpl_a_essay WHERE question_fi = %s",
707  array( "integer" ),
708  array( $this->getId() )
709  );
710 
711  foreach ($this->answers as $answer) {
713  $nextID = $ilDB->nextId('qpl_a_essay');
714  $ilDB->manipulateF(
715  "INSERT INTO qpl_a_essay (answer_id, question_fi, answertext, points) VALUES (%s, %s, %s, %s)",
716  array( "integer", "integer", "text", 'float' ),
717  array(
718  $nextID,
719  $this->getId(),
720  $answer->getAnswertext(),
721  $answer->getPoints()
722  )
723  );
724  }
725  }
726 
733  public function getQuestionType()
734  {
735  return "assTextQuestion";
736  }
737 
745  public function getTextRating()
746  {
747  return $this->text_rating;
748  }
749 
757  public function setTextRating($a_text_rating)
758  {
759  switch ($a_text_rating) {
767  $this->text_rating = $a_text_rating;
768  break;
769  default:
770  $this->text_rating = TEXTGAP_RATING_CASEINSENSITIVE;
771  break;
772  }
773  }
774 
781  public function getAdditionalTableName()
782  {
783  return "qpl_qst_essay";
784  }
785 
790  public function getRTETextWithMediaObjects()
791  {
792  return parent::getRTETextWithMediaObjects();
793  }
794 
798  public function setExportDetailsXLS($worksheet, $startrow, $active_id, $pass)
799  {
800  parent::setExportDetailsXLS($worksheet, $startrow, $active_id, $pass);
801 
802  $solutions = $this->getSolutionValues($active_id, $pass);
803 
804  $i = 1;
805  $worksheet->setCell($startrow + $i, 0, $this->lng->txt("result"));
806  $worksheet->setBold($worksheet->getColumnCoord(0) . ($startrow + $i));
807 
808  require_once 'Modules/Test/classes/class.ilObjAssessmentFolder.php';
809  $assessment_folder = new ilObjAssessmentFolder();
810 
811  $string_escaping_org_value = $worksheet->getStringEscaping();
812  if ($assessment_folder->getExportEssayQuestionsWithHtml() == 1) {
813  $worksheet->setStringEscaping(false);
814  }
815 
816  if (strlen($solutions[0]["value1"])) {
817  $worksheet->setCell($startrow + $i, 2, html_entity_decode($solutions[0]["value1"]));
818  }
819  $i++;
820 
821  $worksheet->setStringEscaping($string_escaping_org_value);
822  return $startrow + $i + 1;
823  }
824 
828  public function toJSON()
829  {
830  include_once("./Services/RTE/classes/class.ilRTE.php");
831  $result = array();
832  $result['id'] = (int) $this->getId();
833  $result['type'] = (string) $this->getQuestionType();
834  $result['title'] = (string) $this->getTitle();
835  $result['question'] = $this->formatSAQuestion($this->getQuestion());
836  $result['nr_of_tries'] = (int) $this->getNrOfTries();
837  $result['shuffle'] = (bool) $this->getShuffle();
838  $result['maxlength'] = (int) $this->getMaxNumOfChars();
839  return json_encode($result);
840  }
841 
842  public function getAnswerCount()
843  {
844  return count($this->answers);
845  }
846 
860  public function addAnswer(
861  $answertext = "",
862  $points = 0.0,
863  $points_unchecked = 0.0,
864  $order = 0,
865  $answerimage = ""
866  ) {
867  include_once "./Modules/TestQuestionPool/classes/class.assAnswerMultipleResponseImage.php";
868 
869  // add answer
870  $answer = new ASS_AnswerMultipleResponseImage($answertext, $points);
871  $this->answers[] = $answer;
872  }
873 
874  public function getAnswers()
875  {
876  return $this->answers;
877  }
878 
888  public function getAnswer($index = 0)
889  {
890  if ($index < 0) {
891  return null;
892  }
893  if (count($this->answers) < 1) {
894  return null;
895  }
896  if ($index >= count($this->answers)) {
897  return null;
898  }
899 
900  return $this->answers[$index];
901  }
902 
911  public function deleteAnswer($index = 0)
912  {
913  if ($index < 0) {
914  return;
915  }
916  if (count($this->answers) < 1) {
917  return;
918  }
919  if ($index >= count($this->answers)) {
920  return;
921  }
922  $answer = $this->answers[$index];
923  if (strlen($answer->getImage())) {
924  $this->deleteImage($answer->getImage());
925  }
926  unset($this->answers[$index]);
927  $this->answers = array_values($this->answers);
928  for ($i = 0; $i < count($this->answers); $i++) {
929  if ($this->answers[$i]->getOrder() > $index) {
930  $this->answers[$i]->setOrder($i);
931  }
932  }
933  }
934 
935  public function getAnswerTableName()
936  {
937  return 'qpl_a_essay';
938  }
939 
946  public function flushAnswers()
947  {
948  $this->answers = array();
949  }
950 
951  public function setAnswers($answers)
952  {
953  if (isset($answers['answer'])) {
954  $count = count($answers['answer']);
955  $withPoints = true;
956  } else {
957  $count = count($answers);
958  $withPoints = false;
959  }
960 
961  $this->flushAnswers();
962 
963  for ($i = 0; $i < $count; $i++) {
964  if ($withPoints) {
965  $this->addAnswer($answers['answer'][$i], $answers['points'][$i]);
966  } else {
967  $this->addAnswer($answers[$i], 0);
968  }
969  }
970  }
971 
973  {
974  global $DIC;
975  $ilDB = $DIC['ilDB'];
976 
977  $result = $ilDB->queryF(
978  "SELECT * FROM qpl_a_essay WHERE question_fi = %s",
979  array('integer'),
980  array($original_id)
981  );
982  if ($result->numRows()) {
983  while ($row = $ilDB->fetchAssoc($result)) {
984  $next_id = $ilDB->nextId('qpl_a_essay');
985  $affectedRows = $ilDB->manipulateF(
986  "INSERT INTO qpl_a_essay (answer_id, question_fi, answertext, points)
987  VALUES (%s, %s, %s, %s)",
988  array('integer','integer','text','float'),
989  array($next_id, $this->getId(), $row["answertext"], $row["points"])
990  );
991  }
992  }
993  }
994 
995  public function getKeywordRelation()
996  {
998  }
999 
1004  public function setKeywordRelation($a_relation)
1005  {
1006  $this->keyword_relation = $a_relation;
1007  }
1008 
1009  public static function getValidScoringModes()
1010  {
1011  return array_merge(self::getScoringModesWithPointsByQuestion(), self::getScoringModesWithPointsByKeyword());
1012  }
1013 
1014  public static function getScoringModesWithPointsByQuestion()
1015  {
1016  return array('non', 'all', 'one');
1017  }
1018 
1019  public static function getScoringModesWithPointsByKeyword()
1020  {
1021  return array('any');
1022  }
1023 
1024 
1035  public function isAnswered($active_id, $pass = null)
1036  {
1037  $numExistingSolutionRecords = assQuestion::getNumExistingSolutionRecords($active_id, $pass, $this->getId());
1038 
1039  return $numExistingSolutionRecords > 0;
1040  }
1041 
1052  public static function isObligationPossible($questionId)
1053  {
1054  return true;
1055  }
1056 
1057  public function countLetters($text)
1058  {
1059  $text = strip_tags($text);
1060 
1061  $text = str_replace('&gt;', '>', $text);
1062  $text = str_replace('&lt;', '<', $text);
1063  $text = str_replace('&nbsp;', ' ', $text);
1064  $text = str_replace('&amp;', '&', $text);
1065 
1066  $text = str_replace("\r\n", "\n", $text);
1067  $text = str_replace("\n", "", $text);
1068 
1069  return ilStr::strLen($text);
1070  }
1071 
1072  public function countWords($text)
1073  {
1074  $text = str_replace('&nbsp;', ' ', $text);
1075 
1076  $text = preg_replace('/[.,:;!?\-_#\'"+*\\/=()&%§$]/m', '', $text);
1077 
1078  $text = preg_replace('/^\s*/m', '', $text);
1079  $text = preg_replace('/\s*$/m', '', $text);
1080  $text = preg_replace('/\s+/m', ' ', $text);
1081 
1082  return count(explode(' ', $text));
1083  }
1084 
1085  public function getLatestAutosaveContent($active_id)
1086  {
1087  $question_fi = $this->getId();
1088 
1089  // Do we have an unauthorized result?
1090  $cntresult = $this->db->query(
1091  '
1092  SELECT count(solution_id) cnt
1093  FROM tst_solutions
1094  WHERE active_fi = ' . $this->db->quote($active_id, 'int') . '
1095  AND question_fi = ' . $this->db->quote($this->getId(), 'int') . '
1096  AND authorized = ' . $this->db->quote(0, 'int')
1097  );
1098  $row = $this->db->fetchAssoc($cntresult);
1099  if ($row['cnt'] > 0) {
1100  $tresult = $this->db->query(
1101  '
1102  SELECT value1
1103  FROM tst_solutions
1104  WHERE active_fi = ' . $this->db->quote($active_id, 'int') . '
1105  AND question_fi = ' . $this->db->quote($this->getId(), 'int') . '
1106  AND authorized = ' . $this->db->quote(0, 'int')
1107  );
1108  $trow = $this->db->fetchAssoc($tresult);
1109  return $trow['value1'];
1110  }
1111  return '';
1112  }
1113 }
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
static _getRichTextEditor()
Returns the identifier for the Rich Text Editor.
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
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
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.
global $DIC
Definition: goto.php:24
setTextRating($a_text_rating)
Sets the rating option for text comparisons.
getQuestion()
Gets the question string of the question object.
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)
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.
$ilUser
Definition: imgupload.php:18
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