ILIAS  release_5-1 Revision 5.0.0-5477-g43f3e3fab5f
class.assOrderingQuestion.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/Test/classes/inc.AssessmentConstants.php';
6require_once './Modules/TestQuestionPool/interfaces/interface.ilObjQuestionScoringAdjustable.php';
7require_once './Modules/TestQuestionPool/interfaces/interface.ilObjAnswerScoringAdjustable.php';
8require_once './Modules/TestQuestionPool/interfaces/interface.iQuestionCondition.php';
9require_once './Modules/TestQuestionPool/classes/class.ilUserQuestionResult.php';
10
25{
34
44
50 var $thumb_geometry = 100;
51
58
59 public $old_ordering_depth = array();
60 public $leveled_ordering = array();
61
74 public function __construct(
75 $title = "",
76 $comment = "",
77 $author = "",
78 $owner = -1,
79 $question = "",
81 )
82 {
83 parent::__construct($title, $comment, $author, $owner, $question);
84 $this->answers = array();
85 $this->ordering_type = $ordering_type;
86 }
87
93 public function isComplete()
94 {
95 if (
96 strlen($this->title) &&
97 $this->author &&
98 $this->question &&
99 count($this->answers) &&
100 $this->getMaximumPoints() > 0
101 )
102 {
103 return true;
104 }
105 return false;
106 }
107
115 public function saveToDb($original_id = "")
116 {
117 global $ilDB;
118
122 parent::saveToDb($original_id);
123 }
124
132 function loadFromDb($question_id)
133 {
134 global $ilDB;
135
136 $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",
137 array("integer"),
138 array($question_id)
139 );
140 if ($result->numRows() == 1)
141 {
142 $data = $ilDB->fetchAssoc($result);
143 $this->setId($question_id);
144 $this->setObjId($data["obj_fi"]);
145 $this->setTitle($data["title"]);
146 $this->setComment($data["description"]);
147 $this->setOriginalId($data["original_id"]);
148 $this->setAuthor($data["author"]);
149 $this->setNrOfTries($data['nr_of_tries']);
150 $this->setPoints($data["points"]);
151 $this->setOwner($data["owner"]);
152 include_once("./Services/RTE/classes/class.ilRTE.php");
153 $this->setQuestion(ilRTE::_replaceMediaObjectImageSrc($data["question_text"], 1));
154 $this->ordering_type = strlen($data["ordering_type"]) ? $data["ordering_type"] : OQ_TERMS;
155 $this->thumb_geometry = $data["thumb_geometry"];
156 $this->element_height = $data["element_height"];
157 $this->setEstimatedWorkingTime(substr($data["working_time"], 0, 2), substr($data["working_time"], 3, 2), substr($data["working_time"], 6, 2));
158
159 try
160 {
161 $this->setAdditionalContentEditingMode($data['add_cont_edit_mode']);
162 }
164 {
165 }
166 }
167
168 $result = $ilDB->queryF("SELECT * FROM qpl_a_ordering WHERE question_fi = %s ORDER BY solution_order ASC",
169 array('integer'),
170 array($question_id)
171 );
172
173 include_once "./Modules/TestQuestionPool/classes/class.assAnswerOrdering.php";
174 if ($result->numRows() > 0)
175 {
176 while ($data = $ilDB->fetchAssoc($result))
177 {
178 include_once("./Services/RTE/classes/class.ilRTE.php");
179 $data["answertext"] = ilRTE::_replaceMediaObjectImageSrc($data["answertext"], 1);
180 array_push($this->answers, new ASS_AnswerOrdering($data["answertext"], $data["random_id"], $data['depth'] ? $data['depth'] : 0));
181 }
182 }
183 parent::loadFromDb($question_id);
184 }
185
191 function duplicate($for_test = true, $title = "", $author = "", $owner = "", $testObjId = null)
192 {
193 if ($this->id <= 0)
194 {
195 // The question has not been saved. It cannot be duplicated
196 return;
197 }
198 // duplicate the question in database
199 $this_id = $this->getId();
200 $thisObjId = $this->getObjId();
201
202 $clone = $this;
203 include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
205 $clone->id = -1;
206
207 if( (int)$testObjId > 0 )
208 {
209 $clone->setObjId($testObjId);
210 }
211
212 if ($title)
213 {
214 $clone->setTitle($title);
215 }
216 if ($author)
217 {
218 $clone->setAuthor($author);
219 }
220 if ($owner)
221 {
222 $clone->setOwner($owner);
223 }
224 if ($for_test)
225 {
226 $clone->saveToDb($original_id);
227 }
228 else
229 {
230 $clone->saveToDb();
231 }
232
233 // copy question page content
234 $clone->copyPageOfQuestion($this_id);
235 // copy XHTML media objects
236 $clone->copyXHTMLMediaObjectsOfQuestion($this_id);
237 // duplicate the image
238 $clone->duplicateImages($this_id, $thisObjId, $clone->getId(), $testObjId);
239
240 $clone->onDuplicate($thisObjId, $this_id, $clone->getObjId(), $clone->getId());
241
242 return $clone->id;
243 }
244
250 function copyObject($target_questionpool_id, $title = "")
251 {
252 if ($this->id <= 0)
253 {
254 // The question has not been saved. It cannot be duplicated
255 return;
256 }
257 // duplicate the question in database
258 $clone = $this;
259 include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
261 $clone->id = -1;
262 $source_questionpool_id = $this->getObjId();
263 $clone->setObjId($target_questionpool_id);
264 if ($title)
265 {
266 $clone->setTitle($title);
267 }
268
269 $clone->saveToDb();
270
271 // copy question page content
272 $clone->copyPageOfQuestion($original_id);
273 // copy XHTML media objects
274 $clone->copyXHTMLMediaObjectsOfQuestion($original_id);
275 // duplicate the image
276 $clone->copyImages($original_id, $source_questionpool_id);
277
278 $clone->onCopy($source_questionpool_id, $original_id, $clone->getObjId(), $clone->getId());
279
280 return $clone->id;
281 }
282
283 public function createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle = "")
284 {
285 if ($this->id <= 0)
286 {
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 {
304 $clone->setTitle($targetQuestionTitle);
305 }
306
307 $clone->saveToDb();
308 // copy question page content
309 $clone->copyPageOfQuestion($sourceQuestionId);
310 // copy XHTML media objects
311 $clone->copyXHTMLMediaObjectsOfQuestion($sourceQuestionId);
312 // duplicate the image
313 $clone->copyImages($sourceQuestionId, $sourceParentId);
314
315 $clone->onCopy($sourceParentId, $sourceQuestionId, $clone->getObjId(), $clone->getId());
316
317 return $clone->id;
318 }
319
320 function duplicateImages($src_question_id, $src_object_id, $dest_question_id, $dest_object_id)
321 {
322 global $ilLog;
323 if ($this->getOrderingType() == OQ_PICTURES || $this->getOrderingType() == OQ_NESTED_PICTURES)
324 {
325 $imagepath_original = $this->getImagePath($src_question_id, $src_object_id);
326 $imagepath = $this->getImagePath($dest_question_id, $dest_object_id);
327
328 if (!file_exists($imagepath)) {
329 ilUtil::makeDirParents($imagepath);
330 }
331 foreach ($this->answers as $answer)
332 {
333 $filename = $answer->getAnswertext();
334 if (!@copy($imagepath_original . $filename, $imagepath . $filename))
335 {
336 $ilLog->write("image could not be duplicated!!!!");
337 }
338 if (@file_exists($imagepath_original. $this->getThumbPrefix(). $filename))
339 {
340 if (!@copy($imagepath_original . $this->getThumbPrefix() . $filename, $imagepath . $this->getThumbPrefix() . $filename))
341 {
342 $ilLog->write("image thumbnail could not be duplicated!!!!");
343 }
344 }
345 }
346 }
347 }
348
349 function copyImages($question_id, $source_questionpool)
350 {
351 global $ilLog;
352 if ($this->getOrderingType() == OQ_PICTURES)
353 {
354 $imagepath = $this->getImagePath();
355 $imagepath_original = str_replace("/$this->id/images", "/$question_id/images", $imagepath);
356 $imagepath_original = str_replace("/$this->obj_id/", "/$source_questionpool/", $imagepath_original);
357 if (!file_exists($imagepath)) {
358 ilUtil::makeDirParents($imagepath);
359 }
360 foreach ($this->answers as $answer)
361 {
362 $filename = $answer->getAnswertext();
363 if (!@copy($imagepath_original . $filename, $imagepath . $filename))
364 {
365 $ilLog->write("Ordering Question image could not be copied: $imagepath_original$filename");
366 }
367 if (@file_exists($imagepath_original. $this->getThumbPrefix(). $filename))
368 {
369 if (!@copy($imagepath_original . $this->getThumbPrefix() . $filename, $imagepath . $this->getThumbPrefix() . $filename))
370 {
371 $ilLog->write("Ordering Question image thumbnail could not be copied: $imagepath_original" . $this->getThumbPrefix() . $filename);
372 }
373 }
374 }
375 }
376 }
377
386 {
387 $this->ordering_type = $ordering_type;
388 }
389
398 {
400 }
401
416 function addAnswer($answertext = "", $solution_order = -1 ,$depth = 0)
417 {
418 include_once "./Modules/TestQuestionPool/classes/class.assAnswerOrdering.php";
419 $answer = new ASS_AnswerOrdering($answertext, $this->getRandomID(), $depth);
420 if (($solution_order >= 0) && ($solution_order < count($this->answers)))
421 {
422 $part1 = array_slice($this->answers, 0, $solution_order);
423 $part2 = array_slice($this->answers, $solution_order);
424 $this->answers = array_merge($part1, array($answer), $part2);
425 }
426 else
427 {
428 array_push($this->answers, $answer);
429 }
430 }
431
432 public function moveAnswerUp($position)
433 {
434 if ($position > 0)
435 {
436 $temp = $this->answers[$position-1];
437 $this->answers[$position-1] = $this->answers[$position];
438 $this->answers[$position] = $temp;
439 }
440 }
441
442 public function moveAnswerDown($position)
443 {
444 if ($position < count($this->answers)-1)
445 {
446 $temp = $this->answers[$position+1];
447 $this->answers[$position+1] = $this->answers[$position];
448 $this->answers[$position] = $temp;
449 }
450 }
451
452 protected function getRandomID()
453 {
454 $random_number = mt_rand(1, 100000);
455 $found = true;
456 while ($found)
457 {
458 $found = false;
459 foreach ($this->getAnswers() as $answer)
460 {
461 if ($answer->getRandomID() == $random_number)
462 {
463 $found = true;
464 $random_number++;
465 }
466 }
467 }
468 return $random_number;
469 }
470
480 function getAnswer($index = 0)
481 {
482 if ($index < 0) return NULL;
483 if (count($this->answers) < 1) return NULL;
484 if ($index >= count($this->answers)) return NULL;
485 return $this->answers[$index];
486 }
487
496 function deleteAnswer($index = 0)
497 {
498 if ($index < 0)
499 {
500 return;
501 }
502 if (count($this->answers) < 1)
503 {
504 return;
505 }
506 if ($index >= count($this->answers))
507 {
508 return;
509 }
510 unset($this->answers[$index]);
511 $this->answers = array_values($this->answers);
512 for ($i = 0; $i < count($this->answers); $i++)
513 {
514 if ($this->answers[$i]->getOrder() > $index)
515 {
516 $this->answers[$i]->setOrder($i);
517 }
518 }
519 }
520
527 function flushAnswers()
528 {
529 $this->answers = array();
530 }
531
539 function getAnswerCount()
540 {
541 return count($this->answers);
542 }
543
551 {
552 if (count($this->answers) == 0)
553 {
554 $max = 0;
555 }
556 else
557 {
558 $max = $this->answers[0]->getSolutionOrder();
559 }
560 foreach ($this->answers as $key => $value)
561 {
562 if ($value->getSolutionOrder() > $max)
563 {
564 $max = $value->getSolutionOrder();
565 }
566 }
567 return $max;
568 }
569
580 public function calculateReachedPoints($active_id, $pass = NULL, $authorizedSolution = true, $returndetails = FALSE)
581 {
582 if( $returndetails )
583 {
584 throw new ilTestException('return details not implemented for '.__METHOD__);
585 }
586
587 global $ilDB;
588
589 $found_value1 = array();
590 $found_value2 = array();
591 if (is_null($pass))
592 {
593 $pass = $this->getSolutionMaxPass($active_id);
594 }
595 $result = $this->getCurrentSolutionResultSet($active_id, $pass, $authorizedSolution);
596 $user_order = array();
597 $nested_solution = false;
598 while ($data = $ilDB->fetchAssoc($result))
599 {
600 if ((strcmp($data["value1"], "") != 0) && (strcmp($data["value2"], "") != 0))
601 {
602 if(strchr( $data['value2'],':') == true)
603 {
604// //i.e. "61463:0" = "random_id:depth"
605 $current_solution = explode(':', $data['value2']);
606
607 $user_order[$current_solution[0]]['index'] = $data["value1"];
608 $user_order[$current_solution[0]]['depth'] = $current_solution[1];
609 $user_order[$current_solution[0]]['random_id'] = $current_solution[0];
610
611 $nested_solution = true;
612 }
613 else
614 {
615 $user_order[$data["value2"]] = $data["value1"];
616 $nested_solution = false;
617 }
618 }
619 }
620
621 $points = $this->calculateReachedPointsForSolution($user_order, $nested_solution);
622
623 return $points;
624 }
625
627 {
628 $user_order = array();
629 $nested_solution = false;
630 foreach($previewSession->getParticipantsSolution() as $val1 => $val2)
631 {
632 if ((strcmp($val1, "") != 0) && (strcmp($val2, "") != 0))
633 {
634 if(strchr( $val2,':') == true)
635 {
636 $current_solution = explode(':', $val2);
637
638 $user_order[$current_solution[0]]['index'] = $val1;
639 $user_order[$current_solution[0]]['depth'] = $current_solution[1];
640 $user_order[$current_solution[0]]['random_id'] = $current_solution[0];
641
642 $nested_solution = true;
643 }
644 else
645 {
646 $user_order[$val2] = $val1;
647 $nested_solution = false;
648 }
649 }
650 }
651
652 return $this->calculateReachedPointsForSolution($user_order, $nested_solution);
653 }
654
661 public function getMaximumPoints()
662 {
663 return $this->getPoints();
664 }
665
666 /*
667 * Returns the encrypted save filename of a matching picture
668 * Images are saved with an encrypted filename to prevent users from
669 * cheating by guessing the solution from the image filename
670 *
671 * @param string $filename Original filename
672 * @return string Encrypted filename
673 */
675 {
676 $extension = "";
677 if (preg_match("/.*\\.(\\w+)$/", $filename, $matches))
678 {
679 $extension = $matches[1];
680 }
681 return md5($filename) . "." . $extension;
682 }
683
684 protected function cleanImagefiles()
685 {
686 if ($this->getOrderingType() == OQ_PICTURES)
687 {
688 if (@file_exists($this->getImagePath()))
689 {
690 $contents = ilUtil::getDir($this->getImagePath());
691 foreach ($contents as $f)
692 {
693 if (strcmp($f['type'], 'file') == 0)
694 {
695 $found = false;
696 foreach ($this->getAnswers() as $answer)
697 {
698 if (strcmp($f['entry'], $answer->getAnswertext()) == 0) $found = true;
699 if (strcmp($f['entry'], $this->getThumbPrefix() . $answer->getAnswertext()) == 0) $found = true;
700 }
701 if (!$found)
702 {
703 if (@file_exists($this->getImagePath() . $f['entry'])) @unlink($this->getImagePath() . $f['entry']);
704 }
705 }
706 }
707 }
708 }
709 else
710 {
711 if (@file_exists($this->getImagePath()))
712 {
714 }
715 }
716 }
717
718 /*
719 * Deletes an imagefile from the system if the file is deleted manually
720 *
721 * @param string $filename Image file filename
722 * @return boolean Success
723 */
724 public function deleteImagefile($filename)
725 {
726 $deletename = $$filename;
727 $result = @unlink($this->getImagePath().$deletename);
728 $result = $result & @unlink($this->getImagePath().$this->getThumbPrefix() . $deletename);
729 return $result;
730 }
731
740 function setImageFile($image_tempfilename, $image_filename, $previous_filename)
741 {
742 $result = TRUE;
743 if (strlen($image_tempfilename))
744 {
745 $image_filename = str_replace(" ", "_", $image_filename);
746 $imagepath = $this->getImagePath();
747 if (!file_exists($imagepath))
748 {
749 ilUtil::makeDirParents($imagepath);
750 }
751 $savename = $image_filename;
752 if (!ilUtil::moveUploadedFile($image_tempfilename, $savename, $imagepath.$savename))
753 {
754 $result = FALSE;
755 }
756 else
757 {
758 // create thumbnail file
759 $thumbpath = $imagepath . $this->getThumbPrefix() . $savename;
760 ilUtil::convertImage($imagepath.$savename, $thumbpath, "JPEG", $this->getThumbGeometry());
761 }
762 if ($result && (strcmp($image_filename, $previous_filename) != 0) && (strlen($previous_filename)))
763 {
764 $this->deleteImagefile($previous_filename);
765 }
766 }
767 return $result;
768 }
769
777 function checkSaveData()
778 {
779 $result = true;
780 if ($this->getOutputType() == OUTPUT_JAVASCRIPT)
781 {
782 if (strlen($_POST["orderresult"]))
783 {
784 return $result;
785 }
786 else if(strlen($_POST['answers_ordering']))
787 {
788 $answers_ordering = $_POST['answers_ordering'];
789 $new_hierarchy = json_decode($answers_ordering);
790 $with_random_id = true;
791 $this->setLeveledOrdering($new_hierarchy, $with_random_id);
792
793 //return value as "random_id:depth"
794 return serialize($this->leveled_ordering);
795 }
796 }
797 $order_values = array();
798 foreach ($_POST as $key => $value)
799 {
800 if (preg_match("/^order_(\d+)/", $key, $matches))
801 {
802 if (strcmp($value, "") != 0)
803 {
804 array_push($order_values, $value);
805 }
806 }
807 }
808 $check_order = array_flip($order_values);
809 if (count($check_order) != count($order_values))
810 {
811 // duplicate order values!!!
812 $result = false;
813 ilUtil::sendInfo($this->lng->txt("duplicate_order_values_entered"), TRUE);
814 }
815 return $result;
816 }
817
826 public function saveWorkingData($active_id, $pass = NULL, $authorized = true)
827 {
828 $saveWorkingDataResult = $this->checkSaveData();
829 if ($saveWorkingDataResult)
830 {
831 if (is_null($pass))
832 {
833 include_once "./Modules/Test/classes/class.ilObjTest.php";
834 $pass = ilObjTest::_getPass($active_id);
835 }
836
837 $this->getProcessLocker()->requestUserSolutionUpdateLock();
838
839 $affectedRows = $this->removeCurrentSolution($active_id, $pass, $authorized);
840
841 $entered_values = 0;
842 foreach($this->getSolutionSubmit() as $val1 => $val2)
843 {
844 $this->saveCurrentSolution($active_id, $pass, $val1, trim($val2), $authorized);
845 $entered_values++;
846 }
847
848 $this->getProcessLocker()->releaseUserSolutionUpdateLock();
849 }
850 if ($entered_values)
851 {
852 include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
854 {
855 $this->logAction($this->lng->txtlng("assessment", "log_user_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
856 }
857 }
858 else
859 {
860 include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
862 {
863 $this->logAction($this->lng->txtlng("assessment", "log_user_not_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
864 }
865 }
866
867 return $saveWorkingDataResult;
868 }
869
870 protected function savePreviewData(ilAssQuestionPreviewSession $previewSession)
871 {
872 if( $this->checkSaveData() )
873 {
874 $previewSession->setParticipantsSolution($this->getSolutionSubmit());
875 }
876 }
877
878 public function saveAdditionalQuestionDataToDb()
879 {
881 global $ilDB;
882
883 // save additional data
884 $ilDB->manipulateF( "DELETE FROM " . $this->getAdditionalTableName() . " WHERE question_fi = %s",
885 array( "integer" ),
886 array( $this->getId() )
887 );
888
889 $ilDB->manipulateF( "INSERT INTO " . $this->getAdditionalTableName() . " (question_fi, ordering_type, thumb_geometry, element_height)
890 VALUES (%s, %s, %s, %s)",
891 array( "integer", "text", "integer", "integer" ),
892 array(
893 $this->getId(),
894 $this->ordering_type,
895 $this->getThumbGeometry(),
896 ($this->getElementHeight() > 20) ? $this->getElementHeight() : NULL
897 )
898 );
899 }
900
901 public function saveAnswerSpecificDataToDb()
902 {
904 global $ilDB;
905
906 $ilDB->manipulateF( "DELETE FROM qpl_a_ordering WHERE question_fi = %s",
907 array( 'integer' ),
908 array( $this->getId() )
909 );
910
911 foreach ($this->answers as $key => $value)
912 {
913 $answer_obj = $this->answers[$key];
914 $next_id = $ilDB->nextId( 'qpl_a_ordering' );
915 $ilDB->insert( 'qpl_a_ordering',
916 array(
917 'answer_id' => array( 'integer', $next_id ),
918 'question_fi' => array( 'integer', $this->getId() ),
919// 'answertext' => array( 'text', ilRTE::_replaceMediaObjectImageSrc( $answer_obj->getAnswertext(), 0 ) ),
920 'answertext' => array( 'text', $answer_obj->getAnswertext()),
921 'solution_order' => array( 'integer', $key ),
922 'random_id' => array( 'integer', $answer_obj->getRandomID() ),
923 'tstamp' => array( 'integer', time() ),
924 'depth' => array( 'integer', $answer_obj->getOrderingDepth() )
925 )
926 );
927 }
928
929 if ($this->getOrderingType() == OQ_PICTURES)
930 {
931 $this->rebuildThumbnails();
932 $this->cleanImagefiles();
933 }
934 }
935
944 protected function reworkWorkingData($active_id, $pass, $obligationsAnswered)
945 {
946 // nothing to rework!
947 }
948
956 {
957 return "assOrderingQuestion";
958 }
959
967 {
968 return "qpl_qst_ordering";
969 }
970
978 {
979 return "qpl_a_ordering";
980 }
981
987 {
988 $text = parent::getRTETextWithMediaObjects();
989 foreach ($this->answers as $index => $answer)
990 {
991 $answer_obj = $this->answers[$index];
992 $text .= $answer_obj->getAnswertext();
993 }
994 return $text;
995 }
996
1000 function &getAnswers()
1001 {
1002 return $this->answers;
1003 }
1004
1012 {
1013 return TRUE;
1014 }
1015
1016 public function supportsNonJsOutput()
1017 {
1018 return false;
1019 }
1020
1033 public function setExportDetailsXLS(&$worksheet, $startrow, $active_id, $pass, &$format_title, &$format_bold)
1034 {
1035 include_once ("./Services/Excel/classes/class.ilExcelUtils.php");
1036 $solutions = $this->getSolutionValues($active_id, $pass);
1037 $sol = array();
1038 foreach ($solutions as $solution)
1039 {
1040 $sol[$solution["value1"]] = $solution["value2"];
1041 }
1042 asort($sol);
1043 $sol = array_keys($sol);
1044 $worksheet->writeString($startrow, 0, ilExcelUtils::_convert_text($this->lng->txt($this->getQuestionType())), $format_title);
1045 $worksheet->writeString($startrow, 1, ilExcelUtils::_convert_text($this->getTitle()), $format_title);
1046 $i = 1;
1047 $answers = $this->getAnswers();
1048 foreach ($sol as $idx)
1049 {
1050 foreach ($solutions as $solution)
1051 {
1052 if ($solution["value1"] == $idx) $worksheet->writeString($startrow + $i, 0, ilExcelUtils::_convert_text($solution["value2"]));
1053 }
1054 $worksheet->writeString($startrow + $i, 1, ilExcelUtils::_convert_text($answers[$idx]->getAnswertext()));
1055 $i++;
1056 }
1057 return $startrow + $i + 1;
1058 }
1059
1060 /*
1061 * Get the thumbnail geometry
1062 *
1063 * @return integer Geometry
1064 */
1065 public function getThumbGeometry()
1066 {
1067 return $this->thumb_geometry;
1068 }
1069
1070 public function getThumbSize()
1071 {
1072 return $this->getThumbGeometry();
1073 }
1074
1075 /*
1076 * Set the thumbnail geometry
1077 *
1078 * @param integer $a_geometry Geometry
1079 */
1080 public function setThumbGeometry($a_geometry)
1081 {
1082 $this->thumb_geometry = ($a_geometry < 1) ? 100 : $a_geometry;
1083 }
1084
1085 /*
1086 * Get the minimum element height
1087 *
1088 * @return integer Height
1089 */
1090 public function getElementHeight()
1091 {
1092 return $this->element_height;
1093 }
1094
1095 /*
1096 * Set the minimum element height
1097 *
1098 * @param integer $a_height Height
1099 */
1100 public function setElementHeight($a_height)
1101 {
1102 $this->element_height = ($a_height < 20) ? "" : $a_height;
1103 }
1104
1105 /*
1106 * Rebuild the thumbnail images with a new thumbnail size
1107 */
1108 public function rebuildThumbnails()
1109 {
1110 if ($this->getOrderingType() == OQ_PICTURES || $this->getOrderingType() == OQ_NESTED_PICTURES)
1111 {
1112 foreach ($this->getAnswers() as $answer)
1113 {
1114 $this->generateThumbForFile($this->getImagePath(), $answer->getAnswertext());
1115 }
1116 }
1117 }
1118
1119 public function getThumbPrefix()
1120 {
1121 return "thumb.";
1122 }
1123
1124 protected function generateThumbForFile($path, $file)
1125 {
1126 $filename = $path . $file;
1127 if (@file_exists($filename))
1128 {
1129 $thumbpath = $path . $this->getThumbPrefix() . $file;
1130 $path_info = @pathinfo($filename);
1131 $ext = "";
1132 switch (strtoupper($path_info['extension']))
1133 {
1134 case 'PNG':
1135 $ext = 'PNG';
1136 break;
1137 case 'GIF':
1138 $ext = 'GIF';
1139 break;
1140 default:
1141 $ext = 'JPEG';
1142 break;
1143 }
1144 ilUtil::convertImage($filename, $thumbpath, $ext, $this->getThumbGeometry());
1145 }
1146 }
1147
1151 public function toJSON()
1152 {
1153 include_once("./Services/RTE/classes/class.ilRTE.php");
1154 $result = array();
1155 $result['id'] = (int) $this->getId();
1156 $result['type'] = (string) $this->getQuestionType();
1157 $result['title'] = (string) $this->getTitle();
1158 $result['question'] = $this->formatSAQuestion($this->getQuestion());
1159 $result['nr_of_tries'] = (int) $this->getNrOfTries();
1160 $result['shuffle'] = (bool) true;
1161 $result['points'] = $this->getPoints();
1162 $result['feedback'] = array(
1163 'onenotcorrect' => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), false)),
1164 'allcorrect' => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), true))
1165 );
1166 if ($this->getOrderingType() == OQ_PICTURES)
1167 {
1168 $result['path'] = $this->getImagePathWeb();
1169 }
1170
1171 $counter = 1;
1172 $answers = array();
1173 foreach ($this->getAnswers() as $answer_obj)
1174 {
1175 $answers[$counter] = $answer_obj->getAnswertext();
1176 $counter++;
1177 }
1178 $answers = $this->getShuffler()->shuffle($answers);
1179 $arr = array();
1180 foreach ($answers as $order => $answer)
1181 {
1182 array_push($arr, array(
1183 "answertext" => (string) $answer,
1184 "order" => (int) $order
1185 ));
1186 }
1187 $result['answers'] = $arr;
1188
1189 $mobs = ilObjMediaObject::_getMobsOfObject("qpl:html", $this->getId());
1190 $result['mobs'] = $mobs;
1191
1192 return json_encode($result);
1193 }
1194
1195 public function removeAnswerImage($index)
1196 {
1197 $answer = $this->answers[$index];
1198 if (is_object($answer))
1199 {
1200 $this->deleteImagefile($answer->getAnswertext());
1201 $answer->setAnswertext('');
1202 }
1203 }
1207 protected function getSolutionSubmit()
1208 {
1209 $solutionSubmit = array();
1210
1211 if(array_key_exists("orderresult", $_POST))
1212 {
1213 $orderresult = $_POST["orderresult"];
1214 if(strlen($orderresult))
1215 {
1216 $orderarray = explode(":", $orderresult);
1217 $ordervalue = 1;
1218 foreach($orderarray as $index)
1219 {
1220 $idmatch = null;
1221 if(preg_match("/id_(\\d+)/", $index, $idmatch))
1222 {
1223 $randomid = $idmatch[1];
1224 foreach($this->getAnswers() as $answeridx => $answer)
1225 {
1226 if($answer->getRandomID() == $randomid)
1227 {
1228 $solutionSubmit[$answeridx] = $ordervalue;
1229 $ordervalue++;
1230 }
1231 }
1232 }
1233 }
1234 }
1235 }
1236 else if($this->getOrderingType() == OQ_NESTED_TERMS || $this->getOrderingType() == OQ_NESTED_PICTURES)
1237 {
1238 $answers_ordering = $_POST['answers_ordering__participant'];
1239 $user_solution_hierarchy = json_decode($answers_ordering);
1240 $with_random_id = true;
1241 $this->setLeveledOrdering($user_solution_hierarchy, $with_random_id);
1242
1243 $index = 0;
1244 foreach($this->leveled_ordering as $random_id => $depth)
1245 {
1246 $value_2 = implode(':', array($random_id, $depth));
1247 $solutionSubmit[$index] = $value_2;
1248 $index++;
1249 }
1250 }
1251 else
1252 {
1253 foreach($_POST as $key => $value)
1254 {
1255 $matches = null;
1256 if(preg_match("/^order_(\d+)/", $key, $matches))
1257 {
1258 if(!(preg_match("/initial_value_\d+/", $value)))
1259 {
1260 if(strlen($value))
1261 {
1262 foreach($this->getAnswers() as $answeridx => $answer)
1263 {
1264 if($answer->getRandomID() == $matches[1])
1265 {
1266 $solutionSubmit[$answeridx] = $value;
1267 }
1268 }
1269 }
1270 }
1271 }
1272 }
1273 }
1274
1275 return $solutionSubmit;
1276 }
1277
1283 protected function calculateReachedPointsForSolution($user_order, $nested_solution)
1284 {
1286 {
1287 ksort($user_order);
1288 $user_order = array_values($user_order);
1289 }
1290
1291 $points = 0;
1292 $correctcount = 0;
1293
1294 foreach($this->answers as $index => $answer)
1295 {
1296 if($nested_solution == true)
1297 {
1298 $random_id = $answer->getRandomID();
1299
1300 if($random_id == $user_order[$random_id]['random_id'] && $answer->getOrderingDepth() == $user_order[$random_id]['depth'] && $index == $user_order[$random_id]['index'])
1301 {
1302 $correctcount++;
1303 }
1304 } else
1305 {
1306 if($index == $user_order[$index])
1307 {
1308 $correctcount++;
1309 }
1310 }
1311 }
1312
1313 if($correctcount == count($this->answers))
1314 {
1315 $points = $this->getPoints();
1316 return $points;
1317 }
1318 return $points;
1319 }
1320
1321 /***
1322 * @param object $child
1323 * @param integer $ordering_depth
1324 * @param bool $with_random_id
1325 */
1326 private function getDepthRecursive($child, $ordering_depth, $with_random_id = false)
1327 {
1328 if($with_random_id == true)
1329 {
1330 // for test ouput
1331 if(is_array($child->children))
1332 {
1333 foreach($child->children as $grand_child)
1334 {
1335 $ordering_depth++;
1336 $this->leveled_ordering[$child->id] = $ordering_depth;
1337 $this->getDepthRecursive($grand_child, $ordering_depth, true);
1338 }
1339 }
1340 else
1341 {
1342 $ordering_depth++;
1343 $this->leveled_ordering[$child->id] = $ordering_depth;
1344 }
1345 }
1346 else
1347 {
1348 if(is_array($child->children))
1349 {
1350 foreach($child->children as $grand_child)
1351 {
1352 $ordering_depth++;
1353 $this->leveled_ordering[] = $ordering_depth;
1354 $this->getDepthRecursive($grand_child, $ordering_depth);
1355 }
1356 }
1357 else
1358 {
1359 $ordering_depth++;
1360 $this->leveled_ordering[] = $ordering_depth;
1361 }
1362 }
1363 }
1364
1365 /***
1366 * @param array $new_hierarchy
1367 * @param bool $with_random_id
1368 */
1369 public function setLeveledOrdering($new_hierarchy, $with_random_id = false)
1370 {
1371 if($with_random_id == true)
1372 {
1373 //for test output
1374 if(is_array($new_hierarchy))
1375 {
1376 foreach($new_hierarchy as $id)
1377 {
1378 $ordering_depth = 0;
1379 $this->leveled_ordering[$id->id] = $ordering_depth;
1380
1381 if(is_array($id->children))
1382 {
1383 foreach($id->children as $child)
1384 {
1385 $this->getDepthRecursive($child, $ordering_depth, true);
1386 }
1387 }
1388 }
1389 }
1390 }
1391 else
1392 {
1393 if(is_array($new_hierarchy))
1394 {
1395 foreach($new_hierarchy as $id)
1396 {
1397 $ordering_depth = 0;
1398 $this->leveled_ordering[] = $ordering_depth;
1399
1400 if(is_array($id->children))
1401 {
1402 foreach($id->children as $child)
1403 {
1404 $this->getDepthRecursive($child, $ordering_depth, $with_random_id);
1405 }
1406 }
1407 }
1408 }
1409 }
1410 }
1411 public function getLeveledOrdering()
1412 {
1414 }
1415
1416 public function getOldLeveledOrdering()
1417 {
1418 global $ilDB;
1419
1420 $res = $ilDB->queryF('SELECT depth FROM qpl_a_ordering WHERE question_fi = %s ORDER BY solution_order ASC',
1421 array('integer'), array($this->getId()));
1422 while($row = $ilDB->fetchAssoc($res))
1423 {
1424 $this->old_ordering_depth[] = $row['depth'];
1425 }
1427 }
1428
1429 /***
1430 * @param integer $a_random_id
1431 * @return integer
1432 */
1433 public function lookupSolutionOrderByRandomid($a_random_id)
1434 {
1435 global $ilDB;
1436
1437 $res = $ilDB->queryF('SELECT solution_order FROM qpl_a_ordering WHERE random_id = %s',
1438 array('integer'), array($a_random_id));
1439 $row = $ilDB->fetchAssoc($res);
1440
1441 return $row['solution_order'];
1442 }
1443
1444 /***
1445 * @param integer $a_random_id
1446 * @param integer $a_question_id
1447 * @return string
1448 */
1449 public function lookupAnswerTextByRandomId($a_random_id, $a_question_id)
1450 {
1451 global $ilDB;
1452
1453 $res = $ilDB->queryF('SELECT answertext FROM qpl_a_ordering WHERE random_id = %s AND question_fi = %s',
1454 array('integer', 'integer'), array($a_random_id, $a_question_id));
1455 $row = $ilDB->fetchAssoc($res);
1456
1457 return $row['answertext'];
1458 }
1459
1460 public function updateLeveledOrdering($a_index, $a_answer_text, $a_depth)
1461 {
1462 global $ilDB;
1463
1464 $ilDB->update('qpl_a_ordering',
1465 array('solution_order'=> array('integer', $a_index),
1466 'depth' => array('integer', $a_depth)),
1467 array('answertext' => array('text', $a_answer_text)));
1468
1469 return true;
1470 }
1471
1480 public function getOperators($expression)
1481 {
1482 require_once "./Modules/TestQuestionPool/classes/class.ilOperatorsExpressionMapping.php";
1484 }
1485
1490 public function getExpressionTypes()
1491 {
1492 return array(
1497 );
1498 }
1499
1508 public function getUserQuestionResult($active_id, $pass)
1509 {
1511 global $ilDB;
1512 $result = new ilUserQuestionResult($this, $active_id, $pass);
1513
1514 $maxStep = $this->lookupMaxStep($active_id, $pass);
1515
1516 if( $maxStep !== null )
1517 {
1518 $data = $ilDB->queryF(
1519 "SELECT value1, value2 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s AND step = %s ORDER BY value1 ASC ",
1520 array("integer", "integer", "integer","integer"),
1521 array($active_id, $pass, $this->getId(), $maxStep)
1522 );
1523 }
1524 else
1525 {
1526 $data = $ilDB->queryF(
1527 "SELECT value1, value2 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s ORDER BY value1 ASC ",
1528 array("integer", "integer", "integer"),
1529 array($active_id, $pass, $this->getId())
1530 );
1531 }
1532
1533 $elements = array();
1534 while($row = $ilDB->fetchAssoc($data))
1535 {
1536
1537 $newKey = explode(":", $row["value2"]);
1538
1539 foreach($this->getAnswers() as $key => $answer)
1540 {
1541 // Images nut supported
1542 if($this->getOrderingType() == OQ_TERMS)
1543 {
1544 if($key == $row["value1"])
1545 {
1546 $elements[$key] = $row["value2"];
1547 break;
1548 }
1549 }
1550 else
1551 {
1552 if($answer->getRandomId() == $newKey[0])
1553 {
1554 $elements[$key] = $row["value1"];
1555 break;
1556 }
1557 }
1558 }
1559 }
1560
1561 ksort($elements);
1562
1563 foreach(array_values($elements) as $element)
1564 {
1565 $result->addKeyValue($element, $element);
1566 }
1567
1568 $points = $this->calculateReachedPoints($active_id, $pass);
1569 $max_points = $this->getMaximumPoints();
1570
1571 $result->setReachedPercentage(($points/$max_points) * 100);
1572
1573 return $result;
1574 }
1575
1584 public function getAvailableAnswerOptions($index = null)
1585 {
1586 if($index !== null)
1587 {
1588 return $this->getAnswer($index);
1589 }
1590 else
1591 {
1592 return $this->getAnswers();
1593 }
1594 }
1595
1599 protected function afterSyncWithOriginal($origQuestionId, $dupQuestionId, $origParentObjId, $dupParentObjId)
1600 {
1601 parent::afterSyncWithOriginal($origQuestionId, $dupQuestionId, $origParentObjId, $dupParentObjId);
1602 $this->duplicateImages($dupQuestionId, $dupParentObjId, $origQuestionId, $origParentObjId);
1603 }
1604}
$result
print $file
$filename
Definition: buildRTE.php:89
Class for ordering question answers.
Class for ordering questions.
getOperators($expression)
Get all available operations for a specific question.
setExportDetailsXLS(&$worksheet, $startrow, $active_id, $pass, &$format_title, &$format_bold)
Creates an Excel worksheet for the detailed cumulated results of this question.
getDepthRecursive($child, $ordering_depth, $with_random_id=false)
getAnswer($index=0)
Returns an ordering answer with a given index.
getExpressionTypes()
Get all available expression types for a specific question.
getQuestionType()
Returns the question type of the question.
copyImages($question_id, $source_questionpool)
getAnswerTableName()
Returns the name of the answer table in the database.
setLeveledOrdering($new_hierarchy, $with_random_id=false)
lookupAnswerTextByRandomId($a_random_id, $a_question_id)
toJSON()
Returns a JSON representation of the question.
& getAnswers()
Returns the answers array.
setOrderingType($ordering_type=OQ_TERMS)
Sets the ordering question type.
saveWorkingData($active_id, $pass=NULL, $authorized=true)
Saves the learners input of the question to the database.
getMaximumPoints()
Returns the maximum points, a learner can reach answering the question.
setImageFile($image_tempfilename, $image_filename, $previous_filename)
Sets the image file and uploads the image to the object's image directory.
flushAnswers()
Deletes all answers.
isComplete()
Returns true, if a ordering question is complete for use.
saveToDb($original_id="")
Saves a assOrderingQuestion object to a database.
calculateReachedPoints($active_id, $pass=NULL, $authorizedSolution=true, $returndetails=FALSE)
Returns the points, a learner has reached answering the question.
savePreviewData(ilAssQuestionPreviewSession $previewSession)
Reworks the allready saved working data if neccessary.
__construct( $title="", $comment="", $author="", $owner=-1, $question="", $ordering_type=OQ_TERMS)
assOrderingQuestion constructor
reworkWorkingData($active_id, $pass, $obligationsAnswered)
Reworks the allready saved working data if neccessary.
deleteAnswer($index=0)
Deletes an answer with a given index.
duplicate($for_test=true, $title="", $author="", $owner="", $testObjId=null)
Duplicates an assOrderingQuestion.
getAvailableAnswerOptions($index=null)
If index is null, the function returns an array with all anwser options Else it returns the specific ...
getAdditionalTableName()
Returns the name of the additional question data table in the database.
getMaxSolutionOrder()
Returns the maximum solution order of all ordering answers.
createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle="")
updateLeveledOrdering($a_index, $a_answer_text, $a_depth)
getOrderingType()
Returns the ordering question type.
loadFromDb($question_id)
Loads a assOrderingQuestion object from a database.
addAnswer($answertext="", $solution_order=-1, $depth=0)
Adds an answer for an ordering choice question.
duplicateImages($src_question_id, $src_object_id, $dest_question_id, $dest_object_id)
afterSyncWithOriginal($origQuestionId, $dupQuestionId, $origParentObjId, $dupParentObjId)
{}
getRTETextWithMediaObjects()
Collects all text in the question which could contain media objects which were created with the Rich ...
supportsJavascriptOutput()
Returns true if the question type supports JavaScript output.
calculateReachedPointsFromPreviewSession(ilAssQuestionPreviewSession $previewSession)
copyObject($target_questionpool_id, $title="")
Copies an assOrderingQuestion object.
calculateReachedPointsForSolution($user_order, $nested_solution)
getAnswerCount()
Returns the number of answers.
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="")
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.
setEstimatedWorkingTime($hour=0, $min=0, $sec=0)
Sets the estimated working time of a question from given hour, minute and second.
getImagePath($question_id=null, $object_id=null)
Returns the image path for web accessable images of a question.
setAuthor($author="")
Sets the authors name of the assQuestion object.
getPoints()
Returns the maximum available points for the question.
getOutputType()
Gets the output type.
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
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.
_convert_text($a_text, $a_target="has been removed")
_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.
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.
Class ilUserQuestionResult.
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 getDir($a_dir, $a_rec=false, $a_sub_dir="")
get directory
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.
static sendInfo($a_info="", $a_keep=false)
Send Info Message to Screen.
$_POST['username']
Definition: cron.php:12
$data
$text
const OQ_NESTED_PICTURES
const OUTPUT_JAVASCRIPT
const OQ_TERMS
const OQ_NESTED_TERMS
const OQ_PICTURES
Ordering question constants.
Class iQuestionCondition.
getUserQuestionResult($active_id, $pass)
Get the user solution for a question by active_id and the test pass.
Interface ilObjAnswerScoringAdjustable.
saveAnswerSpecificDataToDb()
Saves the answer specific records into a question types answer table.
Interface ilObjQuestionScoringAdjustable.
saveAdditionalQuestionDataToDb()
Saves a record to the question types additional data table.
$path
Definition: index.php:22
global $ilDB
$mobs