ILIAS  release_5-1 Revision 5.0.0-5477-g43f3e3fab5f
class.assKprimChoice.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4require_once 'Modules/TestQuestionPool/classes/class.assQuestion.php';
5require_once 'Modules/TestQuestionPool/interfaces/interface.ilObjQuestionScoringAdjustable.php';
6require_once 'Modules/TestQuestionPool/interfaces/interface.ilObjAnswerScoringAdjustable.php';
7require_once 'Modules/TestQuestionPool/interfaces/interface.ilAssSpecificFeedbackOptionLabelProvider.php';
8
16{
18
20
21 const ANSWER_TYPE_SINGLE_LINE = 'singleLine';
22 const ANSWER_TYPE_MULTI_LINE = 'multiLine';
23
24 const OPTION_LABEL_RIGHT_WRONG = 'right_wrong';
25 const OPTION_LABEL_PLUS_MINUS = 'plus_minus';
26 const OPTION_LABEL_APPLICABLE_OR_NOT = 'applicable_or_not';
27 const OPTION_LABEL_ADEQUATE_OR_NOT = 'adequate_or_not';
28 const OPTION_LABEL_CUSTOM = 'customlabel';
29
30 const DEFAULT_THUMB_SIZE = 150;
31 const THUMB_PREFIX = 'thumb.';
32
34
35 private $answerType;
36
37 private $thumbSize;
38
40
41 private $optionLabel;
42
44
46
48
49 private $answers;
50
51 public function __construct($title = '', $comment = '', $author = '', $owner = -1, $question = '')
52 {
53 parent::__construct($title, $comment, $author, $owner, $question);
54
55 $this->shuffleAnswersEnabled = true;
56 $this->answerType = self::ANSWER_TYPE_SINGLE_LINE;
57 $this->thumbSize = self::DEFAULT_THUMB_SIZE;
58 $this->scorePartialSolutionEnabled = true;
59 $this->optionLabel = self::OPTION_LABEL_RIGHT_WRONG;
60 $this->customTrueOptionLabel = '';
61 $this->customFalseOptionLabel = '';
62
63 require_once 'Modules/TestQuestionPool/classes/feedback/class.ilAssConfigurableMultiOptionQuestionFeedback.php';
65
66 $this->answers = array();
67
68 $this->setPoints('');
69 }
70
71 public function getQuestionType()
72 {
73 return 'assKprimChoice';
74 }
75
76 public function getAdditionalTableName()
77 {
78 return "qpl_qst_kprim";
79 }
80
81 public function getAnswerTableName()
82 {
83 return "qpl_a_kprim";
84 }
85
87 {
88 $this->shuffleAnswersEnabled = $shuffleAnswersEnabled;
89 }
90
91 public function isShuffleAnswersEnabled()
92 {
94 }
95
96 public function setAnswerType($answerType)
97 {
98 $this->answerType = $answerType;
99 }
100
101 public function getAnswerType()
102 {
103 return $this->answerType;
104 }
105
106 public function setThumbSize($thumbSize)
107 {
108 $this->thumbSize = $thumbSize;
109 }
110
111 public function getThumbSize()
112 {
113 return $this->thumbSize;
114 }
115
117 {
118 $this->scorePartialSolutionEnabled = $scorePartialSolutionEnabled;
119 }
120
122 {
124 }
125
127 {
128 $this->optionLabel = $optionLabel;
129 }
130
131 public function getOptionLabel()
132 {
133 return $this->optionLabel;
134 }
135
137 {
138 $this->customTrueOptionLabel = $customTrueOptionLabel;
139 }
140
141 public function getCustomTrueOptionLabel()
142 {
144 }
145
147 {
148 $this->customFalseOptionLabel = $customFalseOptionLabel;
149 }
150
152 {
154 }
155
157 {
158 $this->specificFeedbackSetting = $specificFeedbackSetting;
159 }
160
162 {
164 }
165
166 public function setAnswers($answers)
167 {
168 $this->answers = $answers;
169 }
170
171 public function getAnswers()
172 {
173 return $this->answers;
174 }
175
176 public function getAnswer($position)
177 {
178 foreach($this->getAnswers() as $answer)
179 {
180 if($answer->getPosition() == $position)
181 {
182 return $answer;
183 }
184 }
185
186 return null;
187 }
188
189 public function addAnswer(ilAssKprimChoiceAnswer $answer)
190 {
191 $this->answers[] = $answer;
192 }
193
194 public function loadFromDb($questionId)
195 {
196 $res = $this->db->queryF($this->buildQuestionDataQuery(), array('integer'), array($questionId));
197
198 while($data = $this->db->fetchAssoc($res))
199 {
200 $this->setId($questionId);
201
202 $this->setOriginalId($data['original_id']);
203
204 $this->setObjId($data['obj_fi']);
205
206 $this->setTitle($data['title']);
207 $this->setNrOfTries($data['nr_of_tries']);
208 $this->setComment($data['description']);
209 $this->setAuthor($data['author']);
210 $this->setPoints($data['points']);
211 $this->setOwner($data['owner']);
212 $this->setEstimatedWorkingTimeFromDurationString($data['working_time']);
213 $this->setLastChange($data['tstamp']);
214 require_once 'Services/RTE/classes/class.ilRTE.php';
215 $this->setQuestion(ilRTE::_replaceMediaObjectImageSrc($data['question_text'], 1));
216
217 $this->setShuffleAnswersEnabled((bool)$data['shuffle_answers']);
218
219 if( $this->isValidAnswerType($data['answer_type']) )
220 {
221 $this->setAnswerType($data['answer_type']);
222 }
223
224 if( is_numeric($data['thumb_size']) )
225 {
226 $this->setThumbSize((int)$data['thumb_size']);
227 }
228
229 if( $this->isValidOptionLabel($data['opt_label']) )
230 {
231 $this->setOptionLabel($data['opt_label']);
232 }
233
234 $this->setCustomTrueOptionLabel($data['custom_true']);
235 $this->setCustomFalseOptionLabel($data['custom_false']);
236
237 if( $data['score_partsol'] !== null )
238 {
239 $this->setScorePartialSolutionEnabled((bool)$data['score_partsol']);
240 }
241
242 if( isset($data['feedback_setting']) )
243 {
244 $this->setSpecificFeedbackSetting((int)$data['feedback_setting']);
245 }
246
247 try
248 {
249 $this->setAdditionalContentEditingMode($data['add_cont_edit_mode']);
250 }
252 {
253 }
254 }
255
256 $this->loadAnswerData($questionId);
257
258 parent::loadFromDb($questionId);
259 }
260
261 private function loadAnswerData($questionId)
262 {
263 global $ilDB;
264
265 $res = $this->db->queryF(
266 "SELECT * FROM {$this->getAnswerTableName()} WHERE question_fi = %s ORDER BY position ASC",
267 array('integer'), array($questionId)
268 );
269
270 require_once 'Modules/TestQuestionPool/classes/class.ilAssKprimChoiceAnswer.php';
271 require_once 'Services/RTE/classes/class.ilRTE.php';
272
273 while($data = $ilDB->fetchAssoc($res))
274 {
275 $answer = new ilAssKprimChoiceAnswer();
276
277 $answer->setPosition($data['position']);
278
279 $answer->setAnswertext(ilRTE::_replaceMediaObjectImageSrc($data['answertext'], 1));
280
281 $answer->setImageFile($data['imagefile']);
282 $answer->setThumbPrefix($this->getThumbPrefix());
283 $answer->setImageFsDir($this->getImagePath());
284 $answer->setImageWebDir($this->getImagePathWeb());
285
286 $answer->setCorrectness($data['correctness']);
287
288 $this->answers[$answer->getPosition()] = $answer;
289 }
290
291 for( $i = count($this->answers); $i < self::NUM_REQUIRED_ANSWERS; $i++ )
292 {
293 $answer = new ilAssKprimChoiceAnswer();
294
295 $answer->setPosition($i);
296
297 $this->answers[$answer->getPosition()] = $answer;
298 }
299 }
300
301 public function saveToDb($originalId = '')
302 {
303 $this->saveQuestionDataToDb($originalId);
304
307
308 parent::saveToDb($originalId);
309 }
310
312 {
313 $this->db->replace(
314 $this->getAdditionalTableName(),
315 array(
316 'question_fi' => array('integer', $this->getId())
317 ),
318 array(
319 'shuffle_answers' => array('integer', (int)$this->isShuffleAnswersEnabled()),
320 'answer_type' => array('text', $this->getAnswerType()),
321 'thumb_size' => array('integer', (int)$this->getThumbSize()),
322 'opt_label' => array('text', $this->getOptionLabel()),
323 'custom_true' => array('text', $this->getCustomTrueOptionLabel()),
324 'custom_false' => array('text', $this->getCustomFalseOptionLabel()),
325 'score_partsol' => array('integer', (int)$this->isScorePartialSolutionEnabled()),
326 'feedback_setting' => array('integer', (int)$this->getSpecificFeedbackSetting())
327 )
328 );
329 }
330
332 {
333 foreach($this->getAnswers() as $answer)
334 {
335 $this->db->replace(
336 $this->getAnswerTableName(),
337 array(
338 'question_fi' => array('integer', (int)$this->getId()),
339 'position' => array('integer', (int)$answer->getPosition())
340 ),
341 array(
342 'answertext' => array('text', $answer->getAnswertext()),
343 'imagefile' => array('text', $answer->getImageFile()),
344 'correctness' => array('integer', (int)$answer->getCorrectness())
345 )
346 );
347 }
348
349 $this->rebuildThumbnails();
350 }
351
352 public function isComplete()
353 {
354 foreach( array($this->title, $this->author, $this->question) as $text )
355 {
356 if( !strlen($text) )
357 {
358 return false;
359 }
360 }
361
362 if( $this->getMaximumPoints() <= 0 )
363 {
364 return false;
365 }
366
367 foreach( $this->getAnswers() as $answer )
368 {
369 /* @var ilAssKprimChoiceAnswer $answer */
370
371 if( is_null($answer->getCorrectness()) )
372 {
373 return false;
374 }
375
376 if( !strlen($answer->getAnswertext()) && !strlen($answer->getImageFile()) )
377 {
378 return false;
379 }
380 }
381
382 return true;
383 }
384
393 public function saveWorkingData($active_id, $pass = NULL, $authorized = true)
394 {
396 global $ilDB;
397
398 if (is_null($pass))
399 {
400 include_once "./Modules/Test/classes/class.ilObjTest.php";
401 $pass = ilObjTest::_getPass($active_id);
402 }
403
404 $entered_values = 0;
405
406 $this->getProcessLocker()->requestUserSolutionUpdateLock();
407
408 $this->removeCurrentSolution($active_id, $pass, $authorized);
409
410 $solutionSubmit = $this->getSolutionSubmit();
411
412 foreach($solutionSubmit as $answerIndex => $answerValue)
413 {
414 $this->saveCurrentSolution($active_id, $pass, (int)$answerIndex, (int)$answerValue, $authorized);
415 $entered_values++;
416 }
417
418 $this->getProcessLocker()->releaseUserSolutionUpdateLock();
419
420 if ($entered_values)
421 {
422 include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
424 {
425 $this->logAction($this->lng->txtlng("assessment", "log_user_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
426 }
427 }
428 else
429 {
430 include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
432 {
433 $this->logAction($this->lng->txtlng("assessment", "log_user_not_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
434 }
435 }
436
437 return true;
438 }
439
448 protected function reworkWorkingData($active_id, $pass, $obligationsAnswered)
449 {
450 // nothing to do
451 }
452
463 public function calculateReachedPoints($active_id, $pass = NULL, $authorizedSolution = true, $returndetails = FALSE)
464 {
465 if( $returndetails )
466 {
467 throw new ilTestException('return details not implemented for '.__METHOD__);
468 }
469
470 global $ilDB;
471
472 $found_values = array();
473 if (is_null($pass))
474 {
475 $pass = $this->getSolutionMaxPass($active_id);
476 }
477
478 $result = $this->getCurrentSolutionResultSet($active_id, $pass, $authorizedSolution);
479
480 while ($data = $ilDB->fetchAssoc($result))
481 {
482 $found_values[(int)$data['value1']] = (int)$data['value2'];
483 }
484
485 $points = $this->calculateReachedPointsForSolution($found_values, $active_id);
486
487 return $points;
488 }
489
490 public function getValidAnswerTypes()
491 {
492 return array(self::ANSWER_TYPE_SINGLE_LINE, self::ANSWER_TYPE_MULTI_LINE);
493 }
494
496 {
497 $validTypes = $this->getValidAnswerTypes();
498 return in_array($answerType, $validTypes);
499 }
500
502 {
504 }
505
511 {
512 return array(
513 self::ANSWER_TYPE_SINGLE_LINE => $lng->txt('answers_singleline'),
514 self::ANSWER_TYPE_MULTI_LINE => $lng->txt('answers_multiline')
515 );
516 }
517
518 public function getValidOptionLabels()
519 {
520 return array(
521 self::OPTION_LABEL_RIGHT_WRONG,
522 self::OPTION_LABEL_PLUS_MINUS,
523 self::OPTION_LABEL_APPLICABLE_OR_NOT,
524 self::OPTION_LABEL_ADEQUATE_OR_NOT,
525 self::OPTION_LABEL_CUSTOM
526 );
527 }
528
530 {
531 return array(
532 self::OPTION_LABEL_RIGHT_WRONG => $lng->txt('option_label_right_wrong'),
533 self::OPTION_LABEL_PLUS_MINUS => $lng->txt('option_label_plus_minus'),
534 self::OPTION_LABEL_APPLICABLE_OR_NOT => $lng->txt('option_label_applicable_or_not'),
535 self::OPTION_LABEL_ADEQUATE_OR_NOT => $lng->txt('option_label_adequate_or_not'),
536 self::OPTION_LABEL_CUSTOM => $lng->txt('option_label_custom')
537 );
538 }
539
541 {
542 $validLabels = $this->getValidOptionLabels();
543 return in_array($optionLabel, $validLabels);
544 }
545
547 {
548 switch($optionLabel)
549 {
551 return $lng->txt('option_label_right');
552
554 return $lng->txt('option_label_plus');
555
557 return $lng->txt('option_label_applicable');
558
560 return $lng->txt('option_label_adequate');
561
563 return $this->getCustomTrueOptionLabel();
564 }
565 }
566
568 {
569 switch($optionLabel)
570 {
572 return $lng->txt('option_label_wrong');
573
575 return $lng->txt('option_label_minus');
576
578 return $lng->txt('option_label_not_applicable');
579
581 return $lng->txt('option_label_not_adequate');
582
584 return $this->getCustomFalseOptionLabel();
585 }
586 }
587
589 {
590 return sprintf(
591 $lng->txt('kprim_instruction_text'),
592 $this->getTrueOptionLabelTranslation($lng, $optionLabel),
593 $this->getFalseOptionLabelTranslation($lng, $optionLabel)
594 );
595 }
596
597 public function isCustomOptionLabel($labelValue)
598 {
599 return $labelValue == self::OPTION_LABEL_CUSTOM;
600 }
601
602 public function getThumbPrefix()
603 {
604 return self::THUMB_PREFIX;
605 }
606
607 public function rebuildThumbnails()
608 {
609 if( $this->isSingleLineAnswerType($this->getAnswerType()) && $this->getThumbSize() )
610 {
611 foreach ($this->getAnswers() as $answer)
612 {
613 if (strlen($answer->getImageFile()))
614 {
615 $this->generateThumbForFile($answer->getImageFsDir(), $answer->getImageFile());
616 }
617 }
618 }
619 }
620
621 protected function generateThumbForFile($path, $file)
622 {
624 if (@file_exists($filename))
625 {
626 $thumbpath = $path . $this->getThumbPrefix() . $file;
627 $path_info = @pathinfo($filename);
628 $ext = "";
629 switch (strtoupper($path_info['extension']))
630 {
631 case 'PNG':
632 $ext = 'PNG';
633 break;
634 case 'GIF':
635 $ext = 'GIF';
636 break;
637 default:
638 $ext = 'JPEG';
639 break;
640 }
641 ilUtil::convertImage($filename, $thumbpath, $ext, $this->getThumbSize());
642 }
643 }
644
645 public function handleFileUploads($answers, $files)
646 {
647 foreach($answers as $answer)
648 {
649 /* @var ilAssKprimChoiceAnswer $answer */
650
651 if( !isset($files[$answer->getPosition()]) )
652 {
653 continue;
654 }
655
656 $this->handleFileUpload($answer, $files[$answer->getPosition()]);
657 }
658 }
659
660 private function handleFileUpload(ilAssKprimChoiceAnswer $answer, $fileData)
661 {
662 $imagePath = $this->getImagePath();
663
664 if( !file_exists($imagePath) )
665 {
666 ilUtil::makeDirParents($imagePath);
667 }
668
669 $filename = $this->createNewImageFileName($fileData['name'], true);
670
671 $answer->setImageFsDir($imagePath);
672 $answer->setImageFile($filename);
673
674 if( !ilUtil::moveUploadedFile($fileData['tmp_name'], $fileData['name'], $answer->getImageFsPath()) )
675 {
676 return 2;
677 }
678
679 return 0;
680 }
681
682 public function removeAnswerImage($position)
683 {
684 $answer = $this->getAnswer($position);
685
686 if( file_exists($answer->getImageFsPath()) )
687 {
688 ilUtil::delDir($answer->getImageFsPath());
689 }
690
691 if( file_exists($answer->getThumbFsPath()) )
692 {
693 ilUtil::delDir($answer->getThumbFsPath());
694 }
695
696 $answer->setImageFile(null);
697 }
698
699 protected function getSolutionSubmit()
700 {
701 $solutionSubmit = array();
702 foreach($_POST as $key => $value)
703 {
704 $matches = null;
705
706 if(preg_match("/^kprim_choice_result_(\d+)/", $key, $matches))
707 {
708 if(strlen($value))
709 {
710 $solutionSubmit[$matches[1]] = $value;
711 }
712 }
713 }
714 return $solutionSubmit;
715 }
716
717 protected function calculateReachedPointsForSolution($found_values, $active_id = 0)
718 {
719 $numCorrect = 0;
720
721 foreach($this->getAnswers() as $key => $answer)
722 {
723 if( !isset($found_values[$answer->getPosition()]) )
724 {
725 continue;
726 }
727
728 if( $found_values[$answer->getPosition()] == $answer->getCorrectness() )
729 {
730 $numCorrect++;
731 }
732 }
733
734 if( $numCorrect >= self::NUM_REQUIRED_ANSWERS )
735 {
736 $points = $this->getPoints();
737 }
738 elseif( $this->isScorePartialSolutionEnabled() && $numCorrect >= self::PARTIAL_SCORING_NUM_CORRECT_ANSWERS )
739 {
740 $points = $this->getPoints() / 2;
741 }
742 else
743 {
744 $points = 0;
745 }
746
747 if($active_id)
748 {
749 include_once "./Modules/Test/classes/class.ilObjTest.php";
750 $mc_scoring = ilObjTest::_getMCScoring($active_id);
751 if(($mc_scoring == 0) && (count($found_values) == 0))
752 {
753 $points = 0;
754 }
755 }
756 return $points;
757 }
758
759 public function duplicate($for_test = true, $title = "", $author = "", $owner = "", $testObjId = null)
760 {
761 if ($this->id <= 0)
762 {
763 // The question has not been saved. It cannot be duplicated
764 return;
765 }
766 // duplicate the question in database
767 $this_id = $this->getId();
768 $thisObjId = $this->getObjId();
769
770 $clone = $this;
771 include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
773 $clone->id = -1;
774
775 if( (int)$testObjId > 0 )
776 {
777 $clone->setObjId($testObjId);
778 }
779
780 if ($title)
781 {
782 $clone->setTitle($title);
783 }
784
785 if ($author)
786 {
787 $clone->setAuthor($author);
788 }
789 if ($owner)
790 {
791 $clone->setOwner($owner);
792 }
793
794 if ($for_test)
795 {
796 $clone->saveToDb($original_id);
797 }
798 else
799 {
800 $clone->saveToDb();
801 }
802
803 // copy question page content
804 $clone->copyPageOfQuestion($this_id);
805 // copy XHTML media objects
806 $clone->copyXHTMLMediaObjectsOfQuestion($this_id);
807 // duplicate the images
808 $clone->cloneAnswerImages($this_id, $thisObjId, $clone->getId(), $clone->getObjId());
809
810 $clone->onDuplicate($thisObjId, $this_id, $clone->getObjId(), $clone->getId());
811
812 return $clone->id;
813 }
814
815 public function createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle = "")
816 {
817 if ($this->id <= 0)
818 {
819 // The question has not been saved. It cannot be duplicated
820 return;
821 }
822
823 include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
824
825 $sourceQuestionId = $this->id;
826 $sourceParentId = $this->getObjId();
827
828 // duplicate the question in database
829 $clone = $this;
830 $clone->id = -1;
831
832 $clone->setObjId($targetParentId);
833
834 if ($targetQuestionTitle)
835 {
836 $clone->setTitle($targetQuestionTitle);
837 }
838
839 $clone->saveToDb();
840 // copy question page content
841 $clone->copyPageOfQuestion($sourceQuestionId);
842 // copy XHTML media objects
843 $clone->copyXHTMLMediaObjectsOfQuestion($sourceQuestionId);
844 // duplicate the image
845 $clone->cloneAnswerImages($sourceQuestionId, $sourceParentId, $clone->getId(), $clone->getObjId());
846
847 $clone->onCopy($sourceParentId, $sourceQuestionId, $targetParentId, $clone->getId());
848
849 return $clone->id;
850 }
851
855 public function copyObject($target_questionpool_id, $title = "")
856 {
857 if ($this->id <= 0)
858 {
859 // The question has not been saved. It cannot be duplicated
860 return;
861 }
862 // duplicate the question in database
863 $clone = $this;
864 include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
866 $clone->id = -1;
867 $source_questionpool_id = $this->getObjId();
868 $clone->setObjId($target_questionpool_id);
869 if ($title)
870 {
871 $clone->setTitle($title);
872 }
873 $clone->saveToDb();
874 // copy question page content
875 $clone->copyPageOfQuestion($original_id);
876 // copy XHTML media objects
877 $clone->copyXHTMLMediaObjectsOfQuestion($original_id);
878 // duplicate the image
879 $clone->cloneAnswerImages($original_id, $source_questionpool_id, $clone->getId(), $clone->getObjId());
880
881 $clone->onCopy($source_questionpool_id, $original_id, $clone->getObjId(), $clone->getId());
882
883 return $clone->id;
884 }
885
886 protected function beforeSyncWithOriginal($origQuestionId, $dupQuestionId, $origParentObjId, $dupParentObjId)
887 {
888 parent::beforeSyncWithOriginal($origQuestionId, $dupQuestionId, $origParentObjId, $dupParentObjId);
889
890 $question = self::_instanciateQuestion($origQuestionId);
891
892 foreach($question->getAnswers() as $answer)
893 {
894 $question->removeAnswerImage($answer->getPosition());
895 }
896 }
897
898 protected function afterSyncWithOriginal($origQuestionId, $dupQuestionId, $origParentObjId, $dupParentObjId)
899 {
900 parent::afterSyncWithOriginal($origQuestionId, $dupQuestionId, $origParentObjId, $dupParentObjId);
901
902 $this->cloneAnswerImages($dupQuestionId, $dupParentObjId, $origQuestionId, $origParentObjId);
903 }
904
905 protected function cloneAnswerImages($sourceQuestionId, $sourceParentId, $targetQuestionId, $targetParentId)
906 {
908 global $ilLog;
909
910 $sourcePath = $this->buildImagePath($sourceQuestionId, $sourceParentId);
911 $targetPath = $this->buildImagePath($targetQuestionId, $targetParentId);
912
913 foreach($this->getAnswers() as $answer)
914 {
915 $filename = $answer->getImageFile();
916
917 if (strlen($filename))
918 {
919 if (!file_exists($targetPath))
920 {
921 ilUtil::makeDirParents($targetPath);
922 }
923
924 if(!@copy($sourcePath . $filename, $targetPath . $filename))
925 {
926 $ilLog->warning(sprintf(
927 "Could not clone source image '%s' to '%s' (srcQuestionId: %s|tgtQuestionId: %s|srcParentObjId: %s|tgtParentObjId: %s)",
928 $sourcePath . $filename, $targetPath . $filename,
929 $sourceQuestionId, $targetQuestionId, $sourceParentId, $targetParentId
930 ));
931 }
932
933 if(@file_exists($sourcePath . $this->getThumbPrefix() . $filename))
934 {
935 if(!@copy($sourcePath . $this->getThumbPrefix() . $filename, $targetPath . $this->getThumbPrefix() . $filename))
936 {
937 $ilLog->warning(sprintf(
938 "Could not clone thumbnail source image '%s' to '%s' (srcQuestionId: %s|tgtQuestionId: %s|srcParentObjId: %s|tgtParentObjId: %s)",
939 $sourcePath . $this->getThumbPrefix() . $filename, $targetPath . $this->getThumbPrefix() . $filename,
940 $sourceQuestionId, $targetQuestionId, $sourceParentId, $targetParentId
941 ));
942 }
943 }
944 }
945 }
946 }
947
948 protected function getRTETextWithMediaObjects()
949 {
950 $combinedText = parent::getRTETextWithMediaObjects();
951
952 foreach($this->getAnswers() as $answer)
953 {
954 $combinedText .= $answer->getAnswertext();
955 }
956
957 return $combinedText;
958 }
959
964 {
965 foreach($this->getAnswers() as $answer)
966 {
967 /* @var ilAssKprimChoiceAnswer $answer */
968 $answer->setAnswertext( $migrator->migrateToLmContent($answer->getAnswertext()) );
969 }
970 }
971
975 public function toJSON()
976 {
977 $this->lng->loadLanguageModule('assessment');
978
979 require_once './Services/RTE/classes/class.ilRTE.php';
980 $result = array();
981 $result['id'] = (int) $this->getId();
982 $result['type'] = (string) $this->getQuestionType();
983 $result['title'] = (string) $this->getTitle();
984 $result['question'] = $this->formatSAQuestion($this->getQuestion());
985 $result['instruction'] = $this->getInstructionTextTranslation(
986 $this->lng, $this->getOptionLabel()
987 );
988 $result['nr_of_tries'] = (int) $this->getNrOfTries();
989 $result['shuffle'] = (bool) $this->isShuffleAnswersEnabled();
990 $result['feedback'] = array(
991 'onenotcorrect' => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), false)),
992 'allcorrect' => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), true))
993 );
994
995 $result['trueOptionLabel'] = $this->getTrueOptionLabelTranslation($this->lng, $this->getOptionLabel());
996 $result['falseOptionLabel'] = $this->getFalseOptionLabelTranslation($this->lng, $this->getOptionLabel());
997
998 $result['num_allowed_failures'] = $this->getNumAllowedFailures();
999
1000 $answers = array();
1001 $has_image = false;
1002
1003 foreach( $this->getAnswers() as $key => $answer )
1004 {
1005 if( strlen((string)$answer->getImageFile()) )
1006 {
1007 $has_image = true;
1008 }
1009
1010 $answers[] = array(
1011 'answertext' => (string) $this->formatSAQuestion($answer->getAnswertext()),
1012 'correctness' => (bool) $answer->getCorrectness(),
1013 'order' => (int)$answer->getPosition(),
1014 'image' => (string)$answer->getImageFile(),
1015 'feedback' => $this->formatSAQuestion(
1016 $this->feedbackOBJ->getSpecificAnswerFeedbackExportPresentation($this->getId(), $key)
1017 )
1018 );
1019 }
1020
1021 $result['answers'] = $answers;
1022
1023 if($has_image)
1024 {
1025 $result['path'] = $this->getImagePathWeb();
1026 $result['thumb'] = $this->getThumbSize();
1027 }
1028
1029 $mobs = ilObjMediaObject::_getMobsOfObject("qpl:html", $this->getId());
1030 $result['mobs'] = $mobs;
1031
1032 return json_encode($result);
1033 }
1034
1035 private function getNumAllowedFailures()
1036 {
1037 if( $this->isScorePartialSolutionEnabled() )
1038 {
1039 return self::NUM_REQUIRED_ANSWERS - self::PARTIAL_SCORING_NUM_CORRECT_ANSWERS;
1040 }
1041
1042 return 0;
1043 }
1044
1046 {
1047 return 'feedback_correct_kprim';
1048 }
1049
1050 public static function isObligationPossible($questionId)
1051 {
1052 return true;
1053 }
1054
1055 public function isAnswered($active_id, $pass = null)
1056 {
1057 $numExistingSolutionRecords = assQuestion::getNumExistingSolutionRecords($active_id, $pass, $this->getId());
1058
1059 return $numExistingSolutionRecords >= 4;
1060 }
1061
1065 public function setExportDetailsXLS(&$worksheet, $startrow, $active_id, $pass, &$format_title, &$format_bold)
1066 {
1067 require_once 'Services/Excel/classes/class.ilExcelUtils.php';
1068
1069 $solution = $this->getSolutionValues($active_id, $pass);
1070
1071 $worksheet->writeString($startrow, 0, ilExcelUtils::_convert_text($this->lng->txt($this->getQuestionType())), $format_title);
1072 $worksheet->writeString($startrow, 1, ilExcelUtils::_convert_text($this->getTitle()), $format_title);
1073 $i = 1;
1074 foreach($this->getAnswers() as $id => $answer)
1075 {
1076 $worksheet->writeString($startrow + $i, 0, ilExcelUtils::_convert_text($answer->getAnswertext()), $format_bold);
1077 $correctness = FALSE;
1078 foreach($solution as $solutionvalue)
1079 {
1080 if($id == $solutionvalue['value1'])
1081 {
1082 $correctness = $solutionvalue['value2'];
1083 break;
1084 }
1085 }
1086 $worksheet->write($startrow + $i, 1, $correctness);
1087 $i++;
1088 }
1089 return $startrow + $i + 1;
1090 }
1091
1092 public function moveAnswerDown($position)
1093 {
1094 if( $position < 0 || $position >= (self::NUM_REQUIRED_ANSWERS - 1) )
1095 {
1096 return false;
1097 }
1098
1099 for($i = 0, $max = count($this->answers); $i < $max; $i++)
1100 {
1101 if( $i == $position )
1102 {
1103 $movingAnswer = $this->answers[$i];
1104 $targetAnswer = $this->answers[ $i + 1 ];
1105
1106 $movingAnswer->setPosition( $position + 1 );
1107 $targetAnswer->setPosition( $position );
1108
1109 $this->answers[ $i + 1 ] = $movingAnswer;
1110 $this->answers[$i] = $targetAnswer;
1111 }
1112 }
1113 }
1114
1115 public function moveAnswerUp($position)
1116 {
1117 if( $position <= 0 || $position > (self::NUM_REQUIRED_ANSWERS - 1) )
1118 {
1119 return false;
1120 }
1121
1122 for($i = 0, $max = count($this->answers); $i < $max; $i++)
1123 {
1124 if( $i == $position )
1125 {
1126 $movingAnswer = $this->answers[$i];
1127 $targetAnswer = $this->answers[ $i - 1 ];
1128
1129 $movingAnswer->setPosition( $position - 1 );
1130 $targetAnswer->setPosition( $position );
1131
1132 $this->answers[ $i - 1 ] = $movingAnswer;
1133 $this->answers[$i] = $targetAnswer;
1134 }
1135 }
1136
1137 return true;
1138 }
1139}
$result
print $file
$filename
Definition: buildRTE.php:89
getQuestionType()
Returns the question type of the question.
const PARTIAL_SCORING_NUM_CORRECT_ANSWERS
getRTETextWithMediaObjects()
Collects all text in the question which could contain media objects which were created with the Rich ...
toJSON()
Returns a JSON representation of the question.
beforeSyncWithOriginal($origQuestionId, $dupQuestionId, $origParentObjId, $dupParentObjId)
isSingleLineAnswerType($answerType)
setCustomTrueOptionLabel($customTrueOptionLabel)
getAdditionalTableName()
Returns the name of the additional question data table in the database.
setExportDetailsXLS(&$worksheet, $startrow, $active_id, $pass, &$format_title, &$format_bold)
{Creates an Excel worksheet for the detailed cumulated results of this question.}
handleFileUpload(ilAssKprimChoiceAnswer $answer, $fileData)
handleFileUploads($answers, $files)
setCustomFalseOptionLabel($customFalseOptionLabel)
getAnswerTableName()
Returns the name of the answer table in the database.
saveAnswerSpecificDataToDb()
Saves the answer specific records into a question types answer table.
duplicate($for_test=true, $title="", $author="", $owner="", $testObjId=null)
addAnswer(ilAssKprimChoiceAnswer $answer)
generateThumbForFile($path, $file)
removeAnswerImage($position)
copyObject($target_questionpool_id, $title="")
Copies an assMultipleChoice object.
afterSyncWithOriginal($origQuestionId, $dupQuestionId, $origParentObjId, $dupParentObjId)
static isObligationPossible($questionId)
returns boolean wether it is possible to set this question type as obligatory or not considering the ...
loadAnswerData($questionId)
saveAdditionalQuestionDataToDb()
Saves a record to the question types additional data table.
setSpecificFeedbackSetting($specificFeedbackSetting)
createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle="")
getValidOptionLabelsTranslated(ilLanguage $lng)
getTrueOptionLabelTranslation(ilLanguage $lng, $optionLabel)
isAnswered($active_id, $pass=null)
returns boolean wether the question is answered during test pass or not
setAnswerType($answerType)
saveToDb($originalId='')
Saves the question to the database.
getFalseOptionLabelTranslation(ilLanguage $lng, $optionLabel)
calculateReachedPointsForSolution($found_values, $active_id=0)
reworkWorkingData($active_id, $pass, $obligationsAnswered)
Reworks the allready saved working data if neccessary.
isValidOptionLabel($optionLabel)
isCustomOptionLabel($labelValue)
isValidAnswerType($answerType)
calculateReachedPoints($active_id, $pass=NULL, $authorizedSolution=true, $returndetails=FALSE)
Returns the points, a learner has reached answering the question.
lmMigrateQuestionTypeSpecificContent(ilAssSelfAssessmentMigrator $migrator)
getInstructionTextTranslation(ilLanguage $lng, $optionLabel)
setOptionLabel($optionLabel)
loadFromDb($questionId)
Loads the question from the database.
isComplete()
Returns true, if a question is complete for use.
getAnswerTypeSelectOptions(ilLanguage $lng)
setShuffleAnswersEnabled($shuffleAnswersEnabled)
const OPTION_LABEL_APPLICABLE_OR_NOT
__construct($title='', $comment='', $author='', $owner=-1, $question='')
assQuestion constructor
setScorePartialSolutionEnabled($scorePartialSolutionEnabled)
Abstract basic class which is to be extended by the concrete assessment question type classes.
getCurrentSolutionResultSet($active_id, $pass, $authorized=true)
Get a restulset for the current user solution for a this question by active_id and pass.
static _getOriginalId($question_id)
Returns the original id of a question.
formatSAQuestion($a_q)
Format self assessment question.
setId($id=-1)
Sets the id of the assQuestion object.
setOriginalId($original_id)
setObjId($obj_id=0)
Set the object id of the container object.
getSolutionMaxPass($active_id)
Returns the maximum pass a users question solution.
saveQuestionDataToDb($original_id="")
createNewImageFileName($image_filename, $unique=false)
getId()
Gets the id of the assQuestion object.
getObjId()
Get the object id of the container object.
setTitle($title="")
Sets the title string of the assQuestion object.
setOwner($owner="")
Sets the creator/owner ID of the assQuestion object.
setEstimatedWorkingTimeFromDurationString($durationString)
Sets the estimated working time of a question from a given datetime string.
buildImagePath($questionId, $parentObjectId)
getImagePath($question_id=null, $object_id=null)
Returns the image path for web accessable images of a question.
static getNumExistingSolutionRecords($activeId, $pass, $questionId)
returns the number of existing solution records for the given test active / pass and given question i...
setAuthor($author="")
Sets the authors name of the assQuestion object.
getPoints()
Returns the maximum available points for the question.
saveWorkingData($active_id, $pass=NULL, $authorized=true)
Saves the learners input of the question to the database.
getSolutionValues($active_id, $pass=NULL, $authorized=true)
Loads solutions of a given user from the database an returns it.
logAction($logtext="", $active_id="", $question_id="")
Logs an action into the Test&Assessment log.
removeCurrentSolution($active_id, $pass, $authorized=true, $ignoredSolutionIds=array())
getTitle()
Gets the title string of the assQuestion object.
setPoints($a_points)
Sets the maximum available points for the question.
setComment($comment="")
Sets the comment string of the assQuestion object.
setNrOfTries($a_nr_of_tries)
getQuestion()
Gets the question string of the question object.
setAdditionalContentEditingMode($additinalContentEditingMode)
setter for additional content editing mode for this question
static _instanciateQuestion($question_id)
Creates an instance of a question with a given question id.
saveCurrentSolution($active_id, $pass, $value1, $value2, $authorized=true)
setQuestion($question="")
Sets the question string of the question object.
getImagePathWeb()
Returns the web image path for web accessable images of a question.
getMaximumPoints()
Returns the maximum points, a learner can reach answering the question.
setLastChange($lastChange)
_convert_text($a_text, $a_target="has been removed")
language handling
_getLogLanguage()
retrieve the log language for assessment logging
_enabledAssessmentLogging()
check wether assessment logging is enabled or not
_getMobsOfObject($a_type, $a_id, $a_usage_hist_nr=0, $a_lang="-")
get mobs of object
_getPass($active_id)
Retrieves the actual pass of a given user for a given test.
_getMCScoring($active_id)
Gets the scoring type for multiple choice questions.
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...
Base Exception for all Exceptions relating to Modules/Test.
static moveUploadedFile($a_file, $a_name, $a_target, $a_raise_errors=true, $a_mode="move_uploaded")
move uploaded file
static delDir($a_dir, $a_clean_only=false)
removes a dir and all its content (subdirs and files) recursively
static convertImage($a_from, $a_to, $a_target_format="", $a_geometry="", $a_background_color="")
convert image
static makeDirParents($a_dir)
Create a new directory and all parent directories.
$_POST['username']
Definition: cron.php:12
$data
$text
Interface ilObjAnswerScoringAdjustable.
Interface ilObjQuestionScoringAdjustable.
$path
Definition: index.php:22
global $ilDB
$mobs