ILIAS  release_5-2 Revision v5.2.25-18-g3f80b828510
class.assMultipleChoice.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 require_once './Modules/TestQuestionPool/interfaces/interface.iQuestionCondition.php';
9 require_once './Modules/TestQuestionPool/classes/class.ilUserQuestionResult.php';
10 require_once 'Modules/TestQuestionPool/interfaces/interface.ilAssSpecificFeedbackOptionLabelProvider.php';
11 
28 {
36  var $answers;
37 
47 
48  public $isSingleline;
49  public $lastChange;
51 
53  protected $thumb_size;
54 
58  protected $selectionLimit;
59 
63  public function setIsSingleline($isSingleline)
64  {
65  $this->isSingleline = $isSingleline;
66  }
67 
71  public function getIsSingleline()
72  {
73  return $this->isSingleline;
74  }
75 
79  public function setLastChange($lastChange)
80  {
81  $this->lastChange = $lastChange;
82  }
83 
87  public function getLastChange()
88  {
89  return $this->lastChange;
90  }
91 
106  public function __construct(
107  $title = "",
108  $comment = "",
109  $author = "",
110  $owner = -1,
111  $question = "",
112  $output_type = OUTPUT_ORDER
113  )
114  {
115  parent::__construct($title, $comment, $author, $owner, $question);
116  $this->output_type = $output_type;
117  $this->thumb_size = 150;
118  $this->answers = array();
119  $this->shuffle = 1;
120  $this->selectionLimit = null;
121  $this->feedback_setting = 0;
122  }
123 
127  public function getSelectionLimit()
128  {
129  return $this->selectionLimit;
130  }
131 
136  {
137  $this->selectionLimit = $selectionLimit;
138  }
139 
146  function isComplete()
147  {
148  if (strlen($this->title) and ($this->author) and ($this->question) and (count($this->answers)) and ($this->getMaximumPoints() > 0))
149  {
150  return true;
151  }
152  else
153  {
154  return false;
155  }
156  }
157 
163  public function saveToDb($original_id = "")
164  {
168 
169  $this->ensureNoInvalidObligation($this->getId());
170  parent::saveToDb($original_id);
171  }
172 
176  protected function rebuildThumbnails()
177  {
178  if ($this->isSingleline && ($this->getThumbSize()))
179  {
180  foreach ($this->getAnswers() as $answer)
181  {
182  if (strlen($answer->getImage()))
183  {
184  $this->generateThumbForFile($this->getImagePath(), $answer->getImage());
185  }
186  }
187  }
188  }
189 
193  public function getThumbPrefix()
194  {
195  return "thumb.";
196  }
197 
202  protected function generateThumbForFile($path, $file)
203  {
204  $filename = $path . $file;
205  if (@file_exists($filename))
206  {
207  $thumbpath = $path . $this->getThumbPrefix() . $file;
208  $path_info = @pathinfo($filename);
209  $ext = "";
210  switch (strtoupper($path_info['extension']))
211  {
212  case 'PNG':
213  $ext = 'PNG';
214  break;
215  case 'GIF':
216  $ext = 'GIF';
217  break;
218  default:
219  $ext = 'JPEG';
220  break;
221  }
222  ilUtil::convertImage($filename, $thumbpath, $ext, $this->getThumbSize());
223  }
224  }
225 
231  public function loadFromDb($question_id)
232  {
233  global $ilDB;
234  $hasimages = 0;
235 
236  $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",
237  array("integer"),
238  array($question_id)
239  );
240  if ($result->numRows() == 1)
241  {
242  $data = $ilDB->fetchAssoc($result);
243  $this->setId($question_id);
244  $this->setObjId($data["obj_fi"]);
245  $this->setTitle($data["title"]);
246  $this->setNrOfTries($data['nr_of_tries']);
247  $this->setComment($data["description"]);
248  $this->setOriginalId($data["original_id"]);
249  $this->setAuthor($data["author"]);
250  $this->setPoints($data["points"]);
251  $this->setOwner($data["owner"]);
252  include_once("./Services/RTE/classes/class.ilRTE.php");
253  $this->setQuestion(ilRTE::_replaceMediaObjectImageSrc($data["question_text"], 1));
254  $shuffle = (is_null($data['shuffle'])) ? true : $data['shuffle'];
255  $this->setShuffle($shuffle);
256  $this->setEstimatedWorkingTime(substr($data["working_time"], 0, 2), substr($data["working_time"], 3, 2), substr($data["working_time"], 6, 2));
257  $this->setThumbSize($data['thumb_size']);
258  $this->isSingleline = ($data['allow_images']) ? false : true;
259  $this->lastChange = $data['tstamp'];
260  $this->setSelectionLimit((int)$data['selection_limit'] > 0 ? (int)$data['selection_limit'] : null);
261  $this->feedback_setting = $data['feedback_setting'];
262 
263  try
264  {
265  $this->setAdditionalContentEditingMode($data['add_cont_edit_mode']);
266  }
268  {
269  }
270  }
271 
272  $result = $ilDB->queryF("SELECT * FROM qpl_a_mc WHERE question_fi = %s ORDER BY aorder ASC",
273  array('integer'),
274  array($question_id)
275  );
276  include_once "./Modules/TestQuestionPool/classes/class.assAnswerMultipleResponseImage.php";
277  if ($result->numRows() > 0)
278  {
279  while ($data = $ilDB->fetchAssoc($result))
280  {
281  $imagefilename = $this->getImagePath() . $data["imagefile"];
282  if (!@file_exists($imagefilename))
283  {
284  $data["imagefile"] = "";
285  }
286  include_once("./Services/RTE/classes/class.ilRTE.php");
287  $data["answertext"] = ilRTE::_replaceMediaObjectImageSrc($data["answertext"], 1);
288  array_push($this->answers, new ASS_AnswerMultipleResponseImage($data["answertext"], $data["points"], $data["aorder"], $data["points_unchecked"], $data["imagefile"]));
289  }
290  }
291 
292  parent::loadFromDb($question_id);
293  }
294 
298  public function duplicate($for_test = true, $title = "", $author = "", $owner = "", $testObjId = null)
299  {
300  if ($this->id <= 0)
301  {
302  // The question has not been saved. It cannot be duplicated
303  return;
304  }
305  // duplicate the question in database
306  $this_id = $this->getId();
307  $thisObjId = $this->getObjId();
308 
309  $clone = $this;
310  include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
312  $clone->id = -1;
313 
314  if( (int)$testObjId > 0 )
315  {
316  $clone->setObjId($testObjId);
317  }
318 
319  if ($title)
320  {
321  $clone->setTitle($title);
322  }
323 
324  if ($author)
325  {
326  $clone->setAuthor($author);
327  }
328  if ($owner)
329  {
330  $clone->setOwner($owner);
331  }
332 
333  if ($for_test)
334  {
335  $clone->saveToDb($original_id);
336  }
337  else
338  {
339  $clone->saveToDb();
340  }
341 
342  // copy question page content
343  $clone->copyPageOfQuestion($this_id);
344  // copy XHTML media objects
345  $clone->copyXHTMLMediaObjectsOfQuestion($this_id);
346  // duplicate the images
347  $clone->duplicateImages($this_id, $thisObjId);
348 
349  $clone->onDuplicate($thisObjId, $this_id, $clone->getObjId(), $clone->getId());
350 
351  return $clone->id;
352  }
353 
357  public function copyObject($target_questionpool_id, $title = "")
358  {
359  if ($this->id <= 0)
360  {
361  // The question has not been saved. It cannot be duplicated
362  return;
363  }
364  // duplicate the question in database
365  $clone = $this;
366  include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
368  $clone->id = -1;
369  $source_questionpool_id = $this->getObjId();
370  $clone->setObjId($target_questionpool_id);
371  if ($title)
372  {
373  $clone->setTitle($title);
374  }
375  $clone->saveToDb();
376  // copy question page content
377  $clone->copyPageOfQuestion($original_id);
378  // copy XHTML media objects
379  $clone->copyXHTMLMediaObjectsOfQuestion($original_id);
380  // duplicate the image
381  $clone->copyImages($original_id, $source_questionpool_id);
382 
383  $clone->onCopy($source_questionpool_id, $original_id, $clone->getObjId(), $clone->getId());
384 
385  return $clone->id;
386  }
387 
388  public function createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle = "")
389  {
390  if ($this->id <= 0)
391  {
392  // The question has not been saved. It cannot be duplicated
393  return;
394  }
395 
396  include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
397 
398  $sourceQuestionId = $this->id;
399  $sourceParentId = $this->getObjId();
400 
401  // duplicate the question in database
402  $clone = $this;
403  $clone->id = -1;
404 
405  $clone->setObjId($targetParentId);
406 
407  if ($targetQuestionTitle)
408  {
409  $clone->setTitle($targetQuestionTitle);
410  }
411 
412  $clone->saveToDb();
413  // copy question page content
414  $clone->copyPageOfQuestion($sourceQuestionId);
415  // copy XHTML media objects
416  $clone->copyXHTMLMediaObjectsOfQuestion($sourceQuestionId);
417  // duplicate the image
418  $clone->copyImages($sourceQuestionId, $sourceParentId);
419 
420  $clone->onCopy($sourceParentId, $sourceQuestionId, $clone->getObjId(), $clone->getId());
421 
422  return $clone->id;
423  }
424 
431  public function getOutputType()
432  {
433  return $this->output_type;
434  }
435 
443  public function setOutputType($output_type = OUTPUT_ORDER)
444  {
445  $this->output_type = $output_type;
446  }
447 
461  public function addAnswer(
462  $answertext = "",
463  $points = 0.0,
464  $points_unchecked = 0.0,
465  $order = 0,
466  $answerimage = ""
467  )
468  {
469  include_once "./Modules/TestQuestionPool/classes/class.assAnswerMultipleResponseImage.php";
470  if (array_key_exists($order, $this->answers))
471  {
472  // insert answer
473  $answer = new ASS_AnswerMultipleResponseImage($answertext, $points, $order, $points_unchecked, $answerimage);
474  $newchoices = array();
475  for ($i = 0; $i < $order; $i++)
476  {
477  array_push($newchoices, $this->answers[$i]);
478  }
479  array_push($newchoices, $answer);
480  for ($i = $order; $i < count($this->answers); $i++)
481  {
482  $changed = $this->answers[$i];
483  $changed->setOrder($i+1);
484  array_push($newchoices, $changed);
485  }
486  $this->answers = $newchoices;
487  }
488  else
489  {
490  // add answer
491  $answer = new ASS_AnswerMultipleResponseImage($answertext, $points, count($this->answers), $points_unchecked, $answerimage);
492  array_push($this->answers, $answer);
493  }
494  }
495 
502  public function getAnswerCount()
503  {
504  return count($this->answers);
505  }
506 
515  public function getAnswer($index = 0)
516  {
517  if ($index < 0) return NULL;
518  if (count($this->answers) < 1) return NULL;
519  if ($index >= count($this->answers)) return NULL;
520 
521  return $this->answers[$index];
522  }
523 
531  public function deleteAnswer($index = 0)
532  {
533  if ($index < 0) return;
534  if (count($this->answers) < 1) return;
535  if ($index >= count($this->answers)) return;
536  $answer = $this->answers[$index];
537  if (strlen($answer->getImage())) $this->deleteImage($answer->getImage());
538  unset($this->answers[$index]);
539  $this->answers = array_values($this->answers);
540  for ($i = 0; $i < count($this->answers); $i++)
541  {
542  if ($this->answers[$i]->getOrder() > $index)
543  {
544  $this->answers[$i]->setOrder($i);
545  }
546  }
547  }
548 
554  public function flushAnswers()
555  {
556  $this->answers = array();
557  }
558 
564  public function getMaximumPoints()
565  {
566  $points = 0;
567  $allpoints = 0;
568  foreach ($this->answers as $key => $value)
569  {
570  if ($value->getPoints() > $value->getPointsUnchecked())
571  {
572  $allpoints += $value->getPoints();
573  }
574  else
575  {
576  $allpoints += $value->getPointsUnchecked();
577  }
578  }
579  return $allpoints;
580  }
581 
593  public function calculateReachedPoints($active_id, $pass = NULL, $authorizedSolution = true, $returndetails = FALSE)
594  {
595  if( $returndetails )
596  {
597  throw new ilTestException('return details not implemented for '.__METHOD__);
598  }
599 
600  global $ilDB;
601 
602  $found_values = array();
603  if (is_null($pass))
604  {
605  $pass = $this->getSolutionMaxPass($active_id);
606  }
607  $result = $this->getCurrentSolutionResultSet($active_id, $pass, $authorizedSolution);
608  while ($data = $ilDB->fetchAssoc($result))
609  {
610  if (strcmp($data["value1"], "") != 0)
611  {
612  array_push($found_values, $data["value1"]);
613  }
614  }
615 
616  $points = $this->calculateReachedPointsForSolution($found_values, $active_id);
617 
618  return $points;
619  }
620 
621  public function validateSolutionSubmit()
622  {
623  $submit = $this->getSolutionSubmit();
624 
625  if( $this->getSelectionLimit() )
626  {
627  if( count($submit) > $this->getSelectionLimit() )
628  {
629  $failureMsg = sprintf($this->lng->txt('ass_mc_sel_lim_exhausted_hint'),
630  $this->getSelectionLimit(), $this->getAnswerCount()
631  );
632 
633  ilUtil::sendFailure($failureMsg, true);
634  return false;
635  }
636  }
637 
638  return true;
639  }
640 
649  public function saveWorkingData($active_id, $pass = NULL, $authorized = true)
650  {
652  global $ilDB;
653 
654  if (is_null($pass))
655  {
656  include_once "./Modules/Test/classes/class.ilObjTest.php";
657  $pass = ilObjTest::_getPass($active_id);
658  }
659 
660  $entered_values = 0;
661 
662  $this->getProcessLocker()->executeUserSolutionUpdateLockOperation(function() use (&$entered_values, $active_id, $pass, $authorized) {
663 
664  $this->removeCurrentSolution($active_id, $pass, $authorized);
665 
666  $solutionSubmit = $this->getSolutionSubmit();
667 
668  foreach($solutionSubmit as $value)
669  {
670  if(strlen($value))
671  {
672  $this->saveCurrentSolution($active_id, $pass, $value, null, $authorized);
673  $entered_values++;
674  }
675  }
676 
677 // fau: testNav - write a dummy entry for the evil mc questions with "None of the above" checked
678  if (!empty($_POST['mc_none_above']))
679  {
680  $this->saveCurrentSolution($active_id, $pass, 'mc_none_above', null, $authorized);
681  $entered_values++;
682  }
683 // fau.
684  });
685 
686  if ($entered_values)
687  {
688  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
690  {
691  assQuestion::logAction($this->lng->txtlng("assessment", "log_user_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
692  }
693  }
694  else
695  {
696  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
698  {
699  assQuestion::logAction($this->lng->txtlng("assessment", "log_user_not_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
700  }
701  }
702 
703  return true;
704  }
705 
706  public function saveAdditionalQuestionDataToDb()
707  {
709  global $ilDB;
710  $oldthumbsize = 0;
711  if ($this->isSingleline && ($this->getThumbSize()))
712  {
713  // get old thumbnail size
714  $result = $ilDB->queryF( "SELECT thumb_size FROM " . $this->getAdditionalTableName(
715  ) . " WHERE question_fi = %s",
716  array( "integer" ),
717  array( $this->getId() )
718  );
719  if ($result->numRows() == 1)
720  {
721  $data = $ilDB->fetchAssoc( $result );
722  $oldthumbsize = $data['thumb_size'];
723  }
724  }
725 
726  if (!$this->isSingleline)
727  {
728  ilUtil::delDir( $this->getImagePath() );
729  }
730 
731  // save additional data
732  $ilDB->replace( $this->getAdditionalTableName(),
733  array(
734  'shuffle' => array('text', $this->getShuffle()),
735  'allow_images' => array('text', $this->isSingleline ? 0 : 1),
736  'thumb_size' => array('integer', strlen($this->getThumbSize()) ? $this->getThumbSize() : null),
737  'selection_limit' => array('integer', $this->getSelectionLimit()),
738  'feedback_setting' => array('integer', $this->getSpecificFeedbackSetting())
739  ),
740  array(
741  'question_fi' => array('integer', $this->getId())
742  )
743  );
744  }
745 
746  public function saveAnswerSpecificDataToDb()
747  {
749  global $ilDB;
750  $ilDB->manipulateF( "DELETE FROM qpl_a_mc WHERE question_fi = %s",
751  array( 'integer' ),
752  array( $this->getId() )
753  );
754 
755  foreach ($this->answers as $key => $value)
756  {
757  $answer_obj = $this->answers[$key];
758  $next_id = $ilDB->nextId( 'qpl_a_mc' );
759  $ilDB->manipulateF( "INSERT INTO qpl_a_mc (answer_id, question_fi, answertext, points, points_unchecked, aorder, imagefile, tstamp) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)",
760  array( 'integer', 'integer', 'text', 'float', 'float', 'integer', 'text', 'integer' ),
761  array(
762  $next_id,
763  $this->getId(),
764  ilRTE::_replaceMediaObjectImageSrc( $answer_obj->getAnswertext(), 0 ),
765  $answer_obj->getPoints(),
766  $answer_obj->getPointsUnchecked(),
767  $answer_obj->getOrder(),
768  $answer_obj->getImage(),
769  time()
770  )
771  );
772  }
773  $this->rebuildThumbnails();
774  }
775 
779  protected function reworkWorkingData($active_id, $pass, $obligationsAnswered, $authorized)
780  {
781  // nothing to rework!
782  }
783 
784  function syncWithOriginal()
785  {
786  if ($this->getOriginalId())
787  {
788  $this->syncImages();
789  parent::syncWithOriginal();
790  }
791  }
792 
798  public function getQuestionType()
799  {
800  return "assMultipleChoice";
801  }
802 
808  public function getAdditionalTableName()
809  {
810  return "qpl_qst_mc";
811  }
812 
818  public function getAnswerTableName()
819  {
820  return "qpl_a_mc";
821  }
822 
830  public function setImageFile($image_filename, $image_tempfilename = "")
831  {
832  $result = 0;
833  if (!empty($image_tempfilename))
834  {
835  $image_filename = str_replace(" ", "_", $image_filename);
836  $imagepath = $this->getImagePath();
837  if (!file_exists($imagepath))
838  {
839  ilUtil::makeDirParents($imagepath);
840  }
841  if (!ilUtil::moveUploadedFile($image_tempfilename, $image_filename, $imagepath.$image_filename))
842  {
843  $result = 2;
844  }
845  else
846  {
847  include_once "./Services/MediaObjects/classes/class.ilObjMediaObject.php";
848  $mimetype = ilObjMediaObject::getMimeType($imagepath . $image_filename);
849  if (!preg_match("/^image/", $mimetype))
850  {
851  unlink($imagepath . $image_filename);
852  $result = 1;
853  }
854  else
855  {
856  // create thumbnail file
857  if ($this->isSingleline && ($this->getThumbSize()))
858  {
859  $this->generateThumbForFile($imagepath, $image_filename);
860  }
861  }
862  }
863  }
864  return $result;
865  }
866 
872  protected function deleteImage($image_filename)
873  {
874  $imagepath = $this->getImagePath();
875  @unlink($imagepath . $image_filename);
876  $thumbpath = $imagepath . $this->getThumbPrefix() . $image_filename;
877  @unlink($thumbpath);
878  }
879 
880  function duplicateImages($question_id, $objectId = null)
881  {
883  global $ilLog;
884 
885  $imagepath = $this->getImagePath();
886  $imagepath_original = str_replace("/$this->id/images", "/$question_id/images", $imagepath);
887 
888  if( (int)$objectId > 0 )
889  {
890  $imagepath_original = str_replace("/$this->obj_id/", "/$objectId/", $imagepath_original);
891  }
892 
893  foreach ($this->answers as $answer)
894  {
895  $filename = $answer->getImage();
896  if (strlen($filename))
897  {
898  if(!file_exists($imagepath))
899  {
900  ilUtil::makeDirParents($imagepath);
901  }
902 
903  if(file_exists($imagepath_original . $filename))
904  {
905  if(!copy($imagepath_original . $filename, $imagepath . $filename))
906  {
907  $ilLog->warning(sprintf(
908  "Could not clone source image '%s' to '%s' (srcQuestionId: %s|tgtQuestionId: %s|srcParentObjId: %s|tgtParentObjId: %s)",
909  $imagepath_original . $filename, $imagepath . $filename,
910  $question_id, $this->id, $objectId, $this->obj_id
911  ));
912  }
913  }
914 
915  if(file_exists($imagepath_original. $this->getThumbPrefix(). $filename))
916  {
917  if(!copy($imagepath_original . $this->getThumbPrefix() . $filename, $imagepath . $this->getThumbPrefix() . $filename))
918  {
919  $ilLog->warning(sprintf(
920  "Could not clone thumbnail source image '%s' to '%s' (srcQuestionId: %s|tgtQuestionId: %s|srcParentObjId: %s|tgtParentObjId: %s)",
921  $imagepath_original . $this->getThumbPrefix() . $filename, $imagepath . $this->getThumbPrefix() . $filename,
922  $question_id, $this->id, $objectId, $this->obj_id
923  ));
924  }
925  }
926  }
927  }
928  }
929 
930  function copyImages($question_id, $source_questionpool)
931  {
932  global $ilLog;
933  $imagepath = $this->getImagePath();
934  $imagepath_original = str_replace("/$this->id/images", "/$question_id/images", $imagepath);
935  $imagepath_original = str_replace("/$this->obj_id/", "/$source_questionpool/", $imagepath_original);
936  foreach ($this->answers as $answer)
937  {
938  $filename = $answer->getImage();
939  if (strlen($filename))
940  {
941  if (!file_exists($imagepath))
942  {
943  ilUtil::makeDirParents($imagepath);
944  }
945  if (!@copy($imagepath_original . $filename, $imagepath . $filename))
946  {
947  $ilLog->write("image could not be duplicated!!!!", $ilLog->ERROR);
948  $ilLog->write("object: " . print_r($this, TRUE), $ilLog->ERROR);
949  }
950  if (@file_exists($imagepath_original. $this->getThumbPrefix(). $filename))
951  {
952  if (!@copy($imagepath_original . $this->getThumbPrefix() . $filename, $imagepath . $this->getThumbPrefix() . $filename))
953  {
954  $ilLog->write("image thumbnail could not be duplicated!!!!", $ilLog->ERROR);
955  $ilLog->write("object: " . print_r($this, TRUE), $ilLog->ERROR);
956  }
957  }
958  }
959  }
960  }
961 
965  protected function syncImages()
966  {
967  global $ilLog;
968 
969  $imagepath = $this->getImagePath();
970 
971  $question_id = $this->getOriginalId();
972  $originalObjId = parent::lookupParentObjId($this->getOriginalId());
973  $imagepath_original = $this->getImagePath($question_id, $originalObjId);
974 
975  ilUtil::delDir($imagepath_original);
976  foreach ($this->answers as $answer)
977  {
978  $filename = $answer->getImage();
979  if (strlen($filename))
980  {
981  if (@file_exists($imagepath . $filename))
982  {
983  if (!file_exists($imagepath))
984  {
985  ilUtil::makeDirParents($imagepath);
986  }
987  if (!file_exists($imagepath_original))
988  {
989  ilUtil::makeDirParents($imagepath_original);
990  }
991  if (!@copy($imagepath . $filename, $imagepath_original . $filename))
992  {
993  $ilLog->write("image could not be duplicated!!!!", $ilLog->ERROR);
994  $ilLog->write("object: " . print_r($this, TRUE), $ilLog->ERROR);
995  }
996  }
997  if (@file_exists($imagepath . $this->getThumbPrefix() . $filename))
998  {
999  if (!@copy($imagepath . $this->getThumbPrefix() . $filename, $imagepath_original . $this->getThumbPrefix() . $filename))
1000  {
1001  $ilLog->write("image thumbnail could not be duplicated!!!!", $ilLog->ERROR);
1002  $ilLog->write("object: " . print_r($this, TRUE), $ilLog->ERROR);
1003  }
1004  }
1005  }
1006  }
1007  }
1008 
1013  {
1014  $text = parent::getRTETextWithMediaObjects();
1015  foreach ($this->answers as $index => $answer)
1016  {
1017  $text .= $this->feedbackOBJ->getSpecificAnswerFeedbackContent($this->getId(), $index);
1018  $answer_obj = $this->answers[$index];
1019  $text .= $answer_obj->getAnswertext();
1020  }
1021  return $text;
1022  }
1023 
1027  function &getAnswers()
1028  {
1029  return $this->answers;
1030  }
1031 
1035  public function setExportDetailsXLS($worksheet, $startrow, $active_id, $pass)
1036  {
1037  parent::setExportDetailsXLS($worksheet, $startrow, $active_id, $pass);
1038 
1039  $solution = $this->getSolutionValues($active_id, $pass);
1040 
1041  $i = 1;
1042  foreach ($this->getAnswers() as $id => $answer)
1043  {
1044  $worksheet->setCell($startrow + $i, 0, $answer->getAnswertext());
1045  $worksheet->setBold($worksheet->getColumnCoord(0) . ($startrow + $i));
1046  $checked = FALSE;
1047  foreach ($solution as $solutionvalue)
1048  {
1049  if ($id == $solutionvalue["value1"])
1050  {
1051  $checked = TRUE;
1052  }
1053  }
1054  if ($checked)
1055  {
1056  $worksheet->setCell($startrow + $i, 1, 1);
1057  }
1058  else
1059  {
1060  $worksheet->setCell($startrow + $i, 1, 0);
1061  }
1062  $i++;
1063  }
1064 
1065  return $startrow + $i + 1;
1066  }
1067 
1068  public function getThumbSize()
1069  {
1070  return $this->thumb_size;
1071  }
1072 
1073  public function setThumbSize($a_size)
1074  {
1075  $this->thumb_size = $a_size;
1076  }
1077 
1082  {
1083  foreach($this->getAnswers() as $answer)
1084  {
1085  /* @var ASS_AnswerBinaryStateImage $answer */
1086  $answer->setAnswertext( $migrator->migrateToLmContent($answer->getAnswertext()) );
1087  }
1088  }
1089 
1093  public function toJSON()
1094  {
1095  require_once './Services/RTE/classes/class.ilRTE.php';
1096  $result = array();
1097  $result['id'] = (int) $this->getId();
1098  $result['type'] = (string) $this->getQuestionType();
1099  $result['title'] = (string) $this->getTitle();
1100  $result['question'] = $this->formatSAQuestion($this->getQuestion());
1101  $result['nr_of_tries'] = (int) $this->getNrOfTries();
1102  $result['shuffle'] = (bool) $this->getShuffle();
1103  $result['selection_limit'] = (int)$this->getSelectionLimit();
1104  $result['feedback'] = array(
1105  'onenotcorrect' => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), false)),
1106  'allcorrect' => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), true))
1107  );
1108 
1109  $answers = array();
1110  $has_image = false;
1111  foreach ($this->getAnswers() as $key => $answer_obj)
1112  {
1113  if((string) $answer_obj->getImage())
1114  {
1115  $has_image = true;
1116  }
1117  array_push($answers, array(
1118  "answertext" => (string) $this->formatSAQuestion($answer_obj->getAnswertext()),
1119  "points_checked" => (float) $answer_obj->getPointsChecked(),
1120  "points_unchecked" => (float) $answer_obj->getPointsUnchecked(),
1121  "order" => (int) $answer_obj->getOrder(),
1122  "image" => (string) $answer_obj->getImage(),
1123  "feedback" => $this->formatSAQuestion(
1124  $this->feedbackOBJ->getSpecificAnswerFeedbackExportPresentation($this->getId(), $key)
1125  )
1126  ));
1127  }
1128  $result['answers'] = $answers;
1129 
1130  if($has_image)
1131  {
1132  $result['path'] = $this->getImagePathWeb();
1133  $result['thumb'] = $this->getThumbSize();
1134  }
1135 
1136  $mobs = ilObjMediaObject::_getMobsOfObject("qpl:html", $this->getId());
1137  $result['mobs'] = $mobs;
1138 
1139  return json_encode($result);
1140  }
1141 
1142  public function removeAnswerImage($index)
1143  {
1144  $answer = $this->answers[$index];
1145  if (is_object($answer))
1146  {
1147  $this->deleteImage($answer->getImage());
1148  $answer->setImage('');
1149  }
1150  }
1151 
1153  {
1154  global $ilUser;
1155 
1156  $multilineAnswerSetting = $ilUser->getPref("tst_multiline_answers");
1157  if ($multilineAnswerSetting != 1)
1158  {
1159  $multilineAnswerSetting = 0;
1160  }
1161  return $multilineAnswerSetting;
1162  }
1163 
1164  function setMultilineAnswerSetting($a_setting = 0)
1165  {
1166  global $ilUser;
1167  $ilUser->writePref("tst_multiline_answers", $a_setting);
1168  }
1169 
1179  function setSpecificFeedbackSetting($a_feedback_setting)
1180  {
1181  $this->feedback_setting = $a_feedback_setting;
1182  }
1183 
1194  {
1195  if ($this->feedback_setting)
1196  {
1197  return $this->feedback_setting;
1198  }
1199  else
1200  {
1201  return 1;
1202  }
1203  }
1204 
1206  {
1207  return 'feedback_correct_sc_mc';
1208  }
1209 
1221  public function isAnswered($active_id, $pass = NULL)
1222  {
1223  $numExistingSolutionRecords = assQuestion::getNumExistingSolutionRecords($active_id, $pass, $this->getId());
1224 
1225  return $numExistingSolutionRecords > 0;
1226  }
1227 
1239  public static function isObligationPossible($questionId)
1240  {
1242  global $ilDB;
1243 
1244  $query = "
1245  SELECT SUM(points) points_for_checked_answers
1246  FROM qpl_a_mc
1247  WHERE question_fi = %s AND points > 0
1248  ";
1249 
1250  $res = $ilDB->queryF($query, array('integer'), array($questionId));
1251 
1252  $row = $ilDB->fetchAssoc($res);
1253 
1254  return $row['points_for_checked_answers'] > 0;
1255  }
1256 
1265  public function ensureNoInvalidObligation($questionId)
1266  {
1268  global $ilDB;
1269 
1270  $query = "
1271  SELECT SUM(qpl_a_mc.points) points_for_checked_answers,
1272  test_question_id
1273 
1274  FROM tst_test_question
1275 
1276  INNER JOIN qpl_a_mc
1277  ON qpl_a_mc.question_fi = tst_test_question.question_fi
1278 
1279  WHERE tst_test_question.question_fi = %s
1280  AND tst_test_question.obligatory = 1
1281 
1282  GROUP BY test_question_id
1283  ";
1284 
1285  $res = $ilDB->queryF($query, array('integer'), array($questionId));
1286 
1287  $updateTestQuestionIds = array();
1288 
1289  while( $row = $ilDB->fetchAssoc($res) )
1290  {
1291  if( $row['points_for_checked_answers'] <= 0 )
1292  {
1293  $updateTestQuestionIds[] = $row['test_question_id'];
1294  }
1295  }
1296 
1297  if( count($updateTestQuestionIds) )
1298  {
1299  $test_question_id__IN__updateTestQuestionIds = $ilDB->in(
1300  'test_question_id', $updateTestQuestionIds, false, 'integer'
1301  );
1302 
1303  $query = "
1304  UPDATE tst_test_question
1305  SET obligatory = 0
1306  WHERE $test_question_id__IN__updateTestQuestionIds
1307  ";
1308 
1309  $ilDB->manipulate($query);
1310  }
1311  }
1312 
1316  protected function getSolutionSubmit()
1317  {
1318  $solutionSubmit = array();
1319  foreach($_POST as $key => $value)
1320  {
1321  if(preg_match("/^multiple_choice_result_(\d+)/", $key))
1322  {
1323  if(strlen($value))
1324  {
1325  $solutionSubmit[] = $value;
1326  }
1327  }
1328  }
1329  return $solutionSubmit;
1330  }
1331 
1337  protected function calculateReachedPointsForSolution($found_values, $active_id = 0)
1338  {
1339  $points = 0;
1340  foreach($this->answers as $key => $answer)
1341  {
1342  if(in_array($key, $found_values))
1343  {
1344  $points += $answer->getPoints();
1345  } else
1346  {
1347  $points += $answer->getPointsUnchecked();
1348  }
1349  }
1350  if($active_id)
1351  {
1352  include_once "./Modules/Test/classes/class.ilObjTest.php";
1353  $mc_scoring = ilObjTest::_getMCScoring($active_id);
1354  if(($mc_scoring == 0) && (count($found_values) == 0))
1355  {
1356  $points = 0;
1357  }
1358  }
1359  return $points;
1360  }
1361 
1370  public function getOperators($expression)
1371  {
1372  require_once "./Modules/TestQuestionPool/classes/class.ilOperatorsExpressionMapping.php";
1374  }
1375 
1380  public function getExpressionTypes()
1381  {
1382  return array(
1387  );
1388  }
1389 
1398  public function getUserQuestionResult($active_id, $pass)
1399  {
1401  global $ilDB;
1402  $result = new ilUserQuestionResult($this, $active_id, $pass);
1403 
1404  $maxStep = $this->lookupMaxStep($active_id, $pass);
1405 
1406  if( $maxStep !== null )
1407  {
1408  $data = $ilDB->queryF(
1409  "SELECT value1+1 as value1 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s AND step = %s",
1410  array("integer", "integer", "integer","integer"),
1411  array($active_id, $pass, $this->getId(), $maxStep)
1412  );
1413  }
1414  else
1415  {
1416  $data = $ilDB->queryF(
1417  "SELECT value1+1 as value1 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s",
1418  array("integer", "integer", "integer"),
1419  array($active_id, $pass, $this->getId())
1420  );
1421  }
1422 
1423  while($row = $ilDB->fetchAssoc($data))
1424  {
1425  $result->addKeyValue($row["value1"], $row["value1"]);
1426  }
1427 
1428  $points = $this->calculateReachedPoints($active_id, $pass);
1429  $max_points = $this->getMaximumPoints();
1430 
1431  $result->setReachedPercentage(($points/$max_points) * 100);
1432 
1433  return $result;
1434  }
1435 
1444  public function getAvailableAnswerOptions($index = null)
1445  {
1446  if($index !== null)
1447  {
1448  return $this->getAnswer($index);
1449  }
1450  else
1451  {
1452  return $this->getAnswers();
1453  }
1454  }
1455 }
flushAnswers()
Deletes all answers.
static isObligationPossible($questionId)
returns boolean wether it is possible to set this question type as obligatory or not considering the ...
calculateReachedPointsForSolution($found_values, $active_id=0)
static makeDirParents($a_dir)
Create a new directory and all parent directories.
static logAction($logtext="", $active_id="", $question_id="")
Logs an action into the Test&Assessment log.
getId()
Gets the id of the assQuestion object.
addAnswer( $answertext="", $points=0.0, $points_unchecked=0.0, $order=0, $answerimage="")
Adds a possible answer for a multiple choice question.
static _getMobsOfObject($a_type, $a_id, $a_usage_hist_nr=0, $a_lang="-")
get mobs of object
$path
Definition: aliased.php:25
static _getOriginalId($question_id)
Returns the original id of a question.
formatSAQuestion($a_q)
Format self assessment question.
getRTETextWithMediaObjects()
Collects all text in the question which could contain media objects which were created with the Rich ...
$worksheet
toJSON()
Returns a JSON representation of the question.
Class iQuestionCondition.
generateThumbForFile($path, $file)
static _getPass($active_id)
Retrieves the actual pass of a given user for a given test.
isComplete()
Returns true, if a multiple choice question is complete for use.
static getNumExistingSolutionRecords($activeId, $pass, $questionId)
returns the number of existing solution records for the given test active / pass and given question i...
duplicate($for_test=true, $title="", $author="", $owner="", $testObjId=null)
Duplicates an assMultipleChoiceQuestion.
copyObject($target_questionpool_id, $title="")
Copies an assMultipleChoice object.
$result
createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle="")
saveAdditionalQuestionDataToDb()
Saves a record to the question types additional data table.
rebuildThumbnails()
Rebuild the thumbnail images with a new thumbnail size.
reworkWorkingData($active_id, $pass, $obligationsAnswered, $authorized)
{}
isAnswered($active_id, $pass=NULL)
returns boolean wether the question is answered during test pass or not
Abstract basic class which is to be extended by the concrete assessment question type classes...
ASS_AnswerBinaryStateImage is a class for answers with a binary state indicator (checked/unchecked, set/unset) and an image file.
setSelectionLimit($selectionLimit)
setId($id=-1)
Sets the id of the assQuestion object.
getImagePathWeb()
Returns the web image path for web accessable images of a question.
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. ...
Add rich text string
The name of the decorator.
setOutputType($output_type=OUTPUT_ORDER)
Sets the output type of the assMultipleChoice object.
getQuestionType()
Returns the question type of the question.
getUserQuestionResult($active_id, $pass)
Get the user solution for a question by active_id and the test pass.
setNrOfTries($a_nr_of_tries)
setAdditionalContentEditingMode($additinalContentEditingMode)
setter for additional content editing mode for this question
loadFromDb($question_id)
Loads a assMultipleChoice object from a database.
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...
Class for multiple choice tests.
getObjId()
Get the object id of the container object.
getShuffle()
Gets the shuffle flag.
lmMigrateQuestionTypeSpecificContent(ilAssSelfAssessmentMigrator $migrator)
Base Exception for all Exceptions relating to Modules/Test.
saveToDb($original_id="")
Saves a assMultipleChoice object to a database.
deleteAnswer($index=0)
Deletes an answer with a given index.
static _getLogLanguage()
retrieve the log language for assessment logging
setAuthor($author="")
Sets the authors name of the assQuestion object.
static _enabledAssessmentLogging()
check wether assessment logging is enabled or not
getImagePath($question_id=null, $object_id=null)
Returns the image path for web accessable images of a question.
$mobs
Class ilUserQuestionResult.
getAnswerCount()
Returns the number of answers.
saveCurrentSolution($active_id, $pass, $value1, $value2, $authorized=true, $tstamp=null)
static moveUploadedFile($a_file, $a_name, $a_target, $a_raise_errors=true, $a_mode="move_uploaded")
move uploaded file
getSpecificFeedbackSetting()
Gets the current feedback settings in effect for the question.
Interface ilObjAnswerScoringAdjustable.
saveWorkingData($active_id, $pass=NULL, $authorized=true)
Saves the learners input of the question to the database.
getQuestion()
Gets the question string of the question object.
getAvailableAnswerOptions($index=null)
If index is null, the function returns an array with all anwser options Else it returns the specific ...
$ilUser
Definition: imgupload.php:18
__construct( $title="", $comment="", $author="", $owner=-1, $question="", $output_type=OUTPUT_ORDER)
assMultipleChoice constructor
syncImages()
Sync images of a MC question on synchronisation with the original question.
getOperators($expression)
Get all available operations for a specific question.
setIsSingleline($isSingleline)
getAnswer($index=0)
Returns an answer with a given index.
& getAnswers()
Returns a reference to the answers array.
setSpecificFeedbackSetting($a_feedback_setting)
Sets the feedback settings in effect for the question.
deleteImage($image_filename)
Deletes an image file.
getExpressionTypes()
Get all available expression types for a specific question.
Create styles array
The data for the language used.
static sendFailure($a_info="", $a_keep=false)
Send Failure Message to Screen.
saveAnswerSpecificDataToDb()
Saves the answer specific records into a question types answer table.
setPoints($a_points)
Sets the maximum available points for the question.
saveQuestionDataToDb($original_id="")
getMaximumPoints()
Returns the maximum points, a learner can reach answering the question.
setImageFile($image_filename, $image_tempfilename="")
Sets the image file and uploads the image to the object&#39;s image directory.
calculateReachedPoints($active_id, $pass=NULL, $authorizedSolution=true, $returndetails=FALSE)
Returns the points, a learner has reached answering the question.
static getMimeType($a_file, $a_external=false)
get mime type for file
setQuestion($question="")
Sets the question string of the question object.
static convertImage($a_from, $a_to, $a_target_format="", $a_geometry="", $a_background_color="")
convert image
Interface ilObjQuestionScoringAdjustable.
removeCurrentSolution($active_id, $pass, $authorized=true)
getAdditionalTableName()
Returns the name of the additional question data table in the database.
static _getMCScoring($active_id)
Gets the scoring type for multiple choice questions.
global $ilDB
setExportDetailsXLS($worksheet, $startrow, $active_id, $pass)
{}
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...
$text
getAnswerTableName()
Returns the name of the answer table in the database.
getSolutionValues($active_id, $pass=NULL, $authorized=true)
Loads solutions of a given user from the database an returns it.
getTitle()
Gets the title string of the assQuestion object.
Add data(end) time
Method that wraps PHPs time in order to allow simulations with the workflow.
if(!file_exists("$old.txt")) if($old===$new) if(file_exists("$new.txt")) $file
const OUTPUT_ORDER
getOutputType()
Gets the multiple choice output type which is either OUTPUT_ORDER (=0) or OUTPUT_RANDOM (=1)...
setTitle($title="")
Sets the title string of the assQuestion object.
setObjId($obj_id=0)
Set the object id of the container object.
static delDir($a_dir, $a_clean_only=false)
removes a dir and all its content (subdirs and files) recursively
setComment($comment="")
Sets the comment string of the assQuestion object.
$_POST["username"]
setMultilineAnswerSetting($a_setting=0)
copyImages($question_id, $source_questionpool)
setOwner($owner="")
Sets the creator/owner ID of the assQuestion object.