Эх сурвалжийг харах

Allow new type of questions in immediate popup exercises BT#15827

Improve class loading
Julio Montoya 5 жил өмнө
parent
commit
a627bd47b2

+ 2 - 2
main/exercise/Annotation.php

@@ -11,8 +11,8 @@
  */
 class Annotation extends Question
 {
-    public static $typePicture = 'annotation.png';
-    public static $explanationLangVar = 'Annotation';
+    public $typePicture = 'annotation.png';
+    public $explanationLangVar = 'Annotation';
 
     /**
      * Annotation constructor.

+ 2 - 2
main/exercise/Draggable.php

@@ -8,8 +8,8 @@
  */
 class Draggable extends Question
 {
-    public static $typePicture = 'ordering.png';
-    public static $explanationLangVar = 'Draggable';
+    public $typePicture = 'ordering.png';
+    public $explanationLangVar = 'Draggable';
 
     /**
      * Class constructor.

+ 20 - 0
main/exercise/HotSpotDelineation.php

@@ -0,0 +1,20 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+/**
+ * Class HotSpotDelineation.
+ */
+class HotSpotDelineation extends HotSpot
+{
+    public $typePicture = 'hotspot-delineation.png';
+    public $explanationLangVar = 'HotspotDelineation';
+
+    /**
+     * HotSpotDelineation constructor.
+     */
+    public function __construct()
+    {
+        parent::__construct();
+        $this->type = HOT_SPOT_DELINEATION;
+    }
+}

+ 2 - 2
main/exercise/MatchingDraggable.php

@@ -8,8 +8,8 @@
  */
 class MatchingDraggable extends Question
 {
-    public static $typePicture = 'matchingdrag.png';
-    public static $explanationLangVar = 'MatchingDraggable';
+    public $typePicture = 'matchingdrag.png';
+    public $explanationLangVar = 'MatchingDraggable';
 
     /**
      * Class constructor.

+ 2 - 2
main/exercise/MultipleAnswerTrueFalseDegreeCertainty.php

@@ -18,8 +18,8 @@ class MultipleAnswerTrueFalseDegreeCertainty extends Question
     const LEVEL_LIGHTRED = 4;
     const LEVEL_DARKRED = 5;
 
-    public static $typePicture = 'mccert.png';
-    public static $explanationLangVar = 'MultipleAnswerTrueFalseDegreeCertainty';
+    public $typePicture = 'mccert.png';
+    public $explanationLangVar = 'MultipleAnswerTrueFalseDegreeCertainty';
     public $optionsTitle;
     public $options;
 

+ 2 - 2
main/exercise/ReadingComprehension.php

@@ -11,8 +11,8 @@
  */
 class ReadingComprehension extends UniqueAnswer
 {
-    public static $typePicture = 'reading-comprehension.png';
-    public static $explanationLangVar = 'ReadingComprehension';
+    public $typePicture = 'reading-comprehension.png';
+    public $explanationLangVar = 'ReadingComprehension';
 
     /**
      * Defines the different speeds of scrolling for the reading window,

+ 2 - 2
main/exercise/UniqueAnswerImage.php

@@ -10,8 +10,8 @@ use ChamiloSession as Session;
  */
 class UniqueAnswerImage extends UniqueAnswer
 {
-    public static $typePicture = 'uaimg.png';
-    public static $explanationLangVar = 'UniqueAnswerImage';
+    public $typePicture = 'uaimg.png';
+    public $explanationLangVar = 'UniqueAnswerImage';
 
     /**
      * UniqueAnswerImage constructor.

+ 2 - 2
main/exercise/calculated_answer.class.php

@@ -13,8 +13,8 @@ use Webit\Util\EvalMath\EvalMath;
  */
 class CalculatedAnswer extends Question
 {
-    public static $typePicture = 'calculated_answer.png';
-    public static $explanationLangVar = 'CalculatedAnswer';
+    public $typePicture = 'calculated_answer.png';
+    public $explanationLangVar = 'CalculatedAnswer';
 
     /**
      * Constructor.

+ 10 - 7
main/exercise/exercise.class.php

@@ -3,9 +3,11 @@
 
 use Chamilo\CoreBundle\Entity\GradebookLink;
 use Chamilo\CoreBundle\Entity\TrackEHotspot;
+use Chamilo\CourseBundle\Entity\CExerciseCategory;
 use ChamiloSession as Session;
 use Doctrine\DBAL\Types\Type;
 
+
 /**
  * Class Exercise.
  *
@@ -689,7 +691,8 @@ class Exercise
                     }
 
                     // Question type
-                    list($typeImg, $typeExpl) = $objQuestionTmp->get_type_icon_html();
+                    $typeImg = $objQuestionTmp->getTypePicture();
+                    $typeExpl = $objQuestionTmp->getExplanation();
 
                     $question_media = null;
                     if (!empty($objQuestionTmp->parent_id)) {
@@ -1939,7 +1942,7 @@ class Exercise
             $categories = $categoryManager->getCategories(api_get_course_int_id());
             $options = [];
             if (!empty($categories)) {
-                /** @var \Chamilo\CourseBundle\Entity\CExerciseCategory $category */
+                /** @var CExerciseCategory $category */
                 foreach ($categories as $category) {
                     $options[$category->getId()] = $category->getName();
                 }
@@ -3141,10 +3144,11 @@ class Exercise
             if ($questionNum == count($this->questionList)) {
                 $urlTitle = get_lang('EndTest');
             }
+            $url = api_get_path(WEB_CODE_PATH).'exercise/exercise_submit_modal.php?'.api_get_cidreq();
 
             $html .= Display::url(
                 $urlTitle,
-                api_get_path(WEB_CODE_PATH).'exercise/exercise_submit_modal.php?'.http_build_query([
+                $url.'&'.http_build_query([
                     'learnpath_id' => $safe_lp_id,
                     'learnpath_item_id' => $safe_lp_item_id,
                     'learnpath_item_view_id' => $safe_lp_item_view_id,
@@ -3520,7 +3524,6 @@ class Exercise
                 error_log(print_r($extra, 1));
             }
             // Fixes problems with negatives values using intval
-
             $true_score = floatval(trim($extra[0]));
             $false_score = floatval(trim($extra[1]));
             $doubt_score = floatval(trim($extra[2]));
@@ -3612,7 +3615,7 @@ class Exercise
             $answerCorrect = $objAnswerTmp->isCorrect($answerId);
             $answerWeighting = (float) $objAnswerTmp->selectWeighting($answerId);
             $answerAutoId = $objAnswerTmp->selectAutoId($answerId);
-            $answerIid = isset($objAnswerTmp->iid[$answerId]) ? $objAnswerTmp->iid[$answerId] : '';
+            $answerIid = isset($objAnswerTmp->iid[$answerId]) ? (int) $objAnswerTmp->iid[$answerId] : 0;
             $answer_correct_array[$answerId] = (bool) $answerCorrect;
 
             if ($debug) {
@@ -3741,7 +3744,7 @@ class Exercise
                     }
                     $totalScore = $questionScore;
                     break;
-                case MULTIPLE_ANSWER: //2
+                case MULTIPLE_ANSWER:
                     if ($from_database) {
                         $choice = [];
                         $sql = "SELECT answer FROM ".$TBL_TRACK_ATTEMPT."
@@ -4629,7 +4632,7 @@ class Exercise
                                             WHERE
                                                 hotspot_exe_id = $exeId AND
                                                 hotspot_question_id= $questionId AND
-                                                hotspot_answer_id = ".intval($answerIid)."
+                                                hotspot_answer_id = $answerIid
                                             ORDER BY hotspot_id ASC";
                                     $result = Database::query($sql);
 

+ 90 - 59
main/exercise/exercise_submit_modal.php

@@ -26,9 +26,7 @@ $threadhold3 = null;
 
 $exerciseResult = Session::read('exerciseResult');
 $exerciseResultCoordinates = isset($_REQUEST['exerciseResultCoordinates']) ? $_REQUEST['exerciseResultCoordinates'] : null;
-$origin = api_get_origin();
 
-// if origin is learnpath
 $learnpath_id = 0;
 if (isset($_REQUEST['learnpath_id'])) {
     $learnpath_id = (int) $_REQUEST['learnpath_id'];
@@ -46,7 +44,7 @@ if (empty($objExercise)) {
     api_not_allowed();
 }
 
-$_SESSION['hotspot_coord'] = [];
+Session::write('hotspot_coord', []);
 $newQuestionList = Session::read('newquestionList', []);
 $questionList = Session::read('questionList');
 $exerciseId = (int) $_GET['exerciseId'];
@@ -58,73 +56,83 @@ $nbrQuestions = isset($_GET['nbrQuestions']) ? (int) $_GET['nbrQuestions'] : nul
 Session::erase('objExerciseExtra'.$exerciseId);
 Session::erase('exerciseResultExtra'.$exerciseId);
 Session::erase('questionListExtra'.$exerciseId);
-
-// Round-up the coordinates
-$user_array = '';
-if (isset($_GET['hotspot'])) {
-    $coords = explode('/', $_GET['hotspot']);
-    if (is_array($coords) && count($coords) > 0) {
-        foreach ($coords as $coord) {
-            if (!empty($coord)) {
-                list($x, $y) = explode(';', $coord);
-                $user_array .= round($x).';'.round($y).'/';
-            }
-        }
+$choiceValue = isset($_GET['choice']) ? $_GET['choice'] : '';
+if (!empty($choiceValue)) {
+    $choiceValue = json_decode($choiceValue);
+    if (isset($choiceValue->answers)) {
+        $choiceValue = $choiceValue->answers;
     }
 }
 
-$user_array = substr($user_array, 0, -1);
-$choice_value = '';
-if (isset($_GET['choice'])) {
-    $choice_value = (int) $_GET['choice'];
-}
-
 echo '<div id="delineation-container">';
 // Getting the options by js
-if (empty($choice_value)) {
+if (empty($choiceValue)) {
     echo "<script>
         // this works for only radio buttons
-        var f = window.document.frm_exercise;
-        var choice_js='';
+        var f = window.document.frm_exercise;        
+        var choice_js = {answers: []};
         var hotspot = new Array();
         var hotspotcoord = new Array();
-        var counter=0;
-        for ( var i = 0; i < f.elements.length; i++ ) {
-            if (f.elements[i].type=='radio' && f.elements[i].checked) {
-                choice_js = f.elements[i].value;
+        var counter = 0;
+        
+        for (var i = 0; i < f.elements.length; i++) {            
+            if (f.elements[i].type == 'radio' && f.elements[i].checked) {                
+                choice_js.answers.push(f.elements[i].value);
+                counter ++;
+            }
+            
+            if (f.elements[i].type == 'checkbox' && f.elements[i].checked) {
+                choice_js.answers.push(f.elements[i].value);
                 counter ++;
             }
 
-            if (f.elements[i].type=='hidden' ) {
+            if (f.elements[i].type == 'hidden') {
                 var name = f.elements[i].name;
-                if (name.substr(0,7)=='hotspot')
+                
+                if (name.substr(0,7) == 'hotspot') {
                     hotspot.push(f.elements[i].value);
+                }
 
-                if (name.substr(0,20)=='hotspot_coordinates')
+                if (name.substr(0,20) == 'hotspot_coordinates') {
                     hotspotcoord.push(f.elements[i].value);
+                }
             }
         }
 
-        if (counter==0) {
-            choice_js=-1; // this is an error
+        if (counter == 0) {
+            choice_js = -1; // this is an error
+        } else {
+            choice_js = JSON.stringify(choice_js);
         }
-
     ";
     // IMPORTANT
-    //this is the real redirect function
-    //echo 'window.location.href = "exercise_submit_modal.php?learnpath_id='.$learnpath_id.'&learnpath_item_id='.$learnpath_item_id.'&hotspotcoord="+ hotspotcoord + "&hotspot="+ hotspot + "&choice="+ choice_js + "&exerciseId='.$exerciseId.'&num='.$questionNum.'&exerciseType='.$exerciseType.'&origin='.$origin.'&gradebook='.$gradebook.'";';
+    // This is the real redirect function
     echo ' url = "exercise_submit_modal.php?learnpath_id='.$learnpath_id.'&learnpath_item_id='.$learnpath_item_id.'&hotspotcoord="+ hotspotcoord + "&hotspot="+ hotspot + "&choice="+ choice_js + "&exerciseId='.$exerciseId.'&num='.$questionNum.'&exerciseType='.$exerciseType.'&'.api_get_cidreq().'&gradebook='.$gradebook.'";';
     echo "$('#global-modal .modal-body').load(url);";
     echo '</script>';
     exit;
 }
 
+// Round-up the coordinates
+$user_array = '';
+if (isset($_GET['hotspot'])) {
+    $coords = explode('/', $_GET['hotspot']);
+    if (is_array($coords) && count($coords) > 0) {
+        foreach ($coords as $coord) {
+            if (!empty($coord)) {
+                list($x, $y) = explode(';', $coord);
+                $user_array .= round($x).';'.round($y).'/';
+            }
+        }
+    }
+}
+
+$user_array = substr($user_array, 0, -1);
+
 $choice = [];
 $questionId = $questionList[$questionNum];
-// $choice_value => value of the user selection
-$choice[$questionId] = isset($choice_value) ? $choice_value : null;
+$choice[$questionId] = isset($choiceValue) ? $choiceValue : null;
 
-// initializing
 if (!is_array($exerciseResult)) {
     $exerciseResult = [];
 }
@@ -152,7 +160,7 @@ Session::write('exerciseResultCoordinates', $exerciseResultCoordinates);
 
 // creates a temporary Question object
 if (in_array($questionId, $questionList)) {
-    $objQuestionTmp = Question:: read($questionId);
+    $objQuestionTmp = Question::read($questionId);
     $questionName = $objQuestionTmp->selectTitle();
     $questionDescription = $objQuestionTmp->selectDescription();
     $questionWeighting = $objQuestionTmp->selectWeighting();
@@ -166,8 +174,8 @@ $choice = $exerciseResult[$questionId];
 $destination = [];
 $comment = '';
 $next = 1;
-$_SESSION['hotspot_coord'] = [];
-$_SESSION['hotspot_dest'] = [];
+Session::write('hotspot_coord', []);
+Session::write('hotspot_dest', []);
 $overlap_color = $missing_color = $excess_color = false;
 $organs_at_risk_hit = 0;
 $wrong_results = false;
@@ -175,7 +183,16 @@ $hot_spot_load = false;
 $questionScore = 0;
 $totalScore = 0;
 
-if (!empty($choice_value)) {
+switch ($answerType) {
+    case MULTIPLE_ANSWER:
+        $choiceValue = array_combine(array_values($choiceValue), array_values($choiceValue));
+        break;
+}
+ob_start();
+$result = $objExercise->manage_answer(0, $questionId, $choiceValue, 'exercise_show', null, false);
+$contents = ob_get_clean();
+/*
+if (!empty($choiceValue)) {
     for ($answerId = 1; $answerId <= $nbrAnswers; $answerId++) {
         $answer = $objAnswerTmp->selectAnswer($answerId);
         $answerComment = $objAnswerTmp->selectComment($answerId);
@@ -189,10 +206,22 @@ if (!empty($choice_value)) {
         $delineation_cord = $objAnswerTmp->selectHotspotCoordinates(1);
         $answer_delineation_destination = $objAnswerTmp->selectDestination(1);
 
+        var_dump($choiceValue);
         switch ($answerType) {
-            // for unique answer
+            case CALCULATED_ANSWER:
+                break;
+            case DRAGGABLE:
+                break;
+            case MULTIPLE_ANSWER:
+                $studentChoice = $choiceValue == $numAnswer ? 1 : 0;
+                if ($studentChoice) {
+                    $questionScore += $answerWeighting;
+                    $totalScore += $answerWeighting;
+                    $newQuestionList[] = $questionId;
+                }
+                break;
             case UNIQUE_ANSWER:
-                $studentChoice = $choice_value == $numAnswer ? 1 : 0;
+                $studentChoice = $choiceValue == $numAnswer ? 1 : 0;
                 if ($studentChoice) {
                     $questionScore += $answerWeighting;
                     $totalScore += $answerWeighting;
@@ -363,7 +392,7 @@ if (!empty($choice_value)) {
                         );
                     }
 
-                    if ($overlap == false) {
+                    if ($overlap == false) $contents{
                         //all good, no overlap
                         $next = 1;
                         continue;
@@ -446,11 +475,11 @@ if (!empty($choice_value)) {
         <td><div style="color:'.$missing_color.'">'.(($final_missing < 0) ? 0 : intval($final_missing)).'</div></td>
     </tr>
     </table>';
-}
+}*/
 Session::write('newquestionList', $newQuestionList);
 $links = '';
 if ($objExercise->getFeedbackType() === EXERCISE_FEEDBACK_TYPE_DIRECT) {
-    if (isset($choice_value) && $choice_value == -1) {
+    if (isset($choiceValue) && $choiceValue == -1) {
         if ($answerType != HOT_SPOT_DELINEATION) {
             $links .= '<a href="#" onclick="tb_remove();">'.get_lang('ChooseAnAnswer').'</a><br />';
         }
@@ -553,18 +582,16 @@ if ($destinationId == -1) {
 echo '<script>
 function SendEx(num) {
     if (num == -1) {
-        window.location.href = "exercise_result.php?take_session=1&exerciseId='.$exerciseId.'&num="+num+"&exerciseType='.$exerciseType.'&origin='.$origin.'&learnpath_item_id='.$learnpath_item_id.'&learnpath_id='.$learnpath_id.'";
+        window.location.href = "exercise_result.php?'.api_get_cidreq().'&take_session=1&exerciseId='.$exerciseId.'&num="+num+"&exerciseType='.$exerciseType.'&learnpath_item_id='.$learnpath_item_id.'&learnpath_id='.$learnpath_id.'";
     } else {
         num -= 1;
-        window.location.href = "exercise_submit.php?tryagain=1&exerciseId='.$exerciseId.'&num="+num+"&exerciseType='.$exerciseType.'&origin='.$origin.'&learnpath_item_id='.$learnpath_item_id.'&learnpath_id='.$learnpath_id.'";
-    }
-    
+        window.location.href = "exercise_submit.php?'.api_get_cidreq().'&tryagain=1&exerciseId='.$exerciseId.'&num="+num+"&exerciseType='.$exerciseType.'&learnpath_item_id='.$learnpath_item_id.'&learnpath_id='.$learnpath_id.'";
+    }    
     return false;
 }
 </script>';
 
 if (!empty($links)) {
-    //echo '<h1><div style="color:#333;">'.get_lang('Feedback').'</div></h1>';
     if ($answerType == HOT_SPOT_DELINEATION) {
         if ($organs_at_risk_hit > 0) {
             $message .= '<br />'.get_lang('ResultIs').' <b>'.get_lang('Unacceptable').'</b><br />';
@@ -579,7 +606,12 @@ if (!empty($links)) {
         echo '<br />';
         echo $message;
     } else {
-        echo '<p>'.$comment.'</p>';
+        echo $objQuestionTmp->return_header(
+            $objExercise,
+            $questionNum,
+            []
+        );
+        echo '<p>'.$contents.'</p>';
     }
     echo '<div style="padding-left: 450px"><h5>'.$links.'</h5></div>';
     echo '</div>';
@@ -589,15 +621,14 @@ if (!empty($links)) {
     // Resetting the exerciseResult variable
     Session::write('exerciseResult', $exerciseResult);
 
-    //save this variables just in case the exercise loads an LP with other exercise
-    $_SESSION['objExerciseExtra'.$exerciseId] = $_SESSION['objExercise'];
-    $_SESSION['exerciseResultExtra'.$exerciseId] = $_SESSION['exerciseResult'];
-    $_SESSION['questionListExtra'.$exerciseId] = $_SESSION['questionList'];
+    // Save this variables just in case the exercise loads an LP with other exercise
+    Session::write('objExerciseExtra'.$exerciseId, Session::read('objExercise'));
+    Session::write('exerciseResultExtra'.$exerciseId, Session::read('exerciseResult'));
+    Session::write('questionListExtra'.$exerciseId, Session::read('questionList'));
 } else {
     $questionNum++;
     echo '<script>
             window.location.href = "exercise_submit.php?exerciseId='.$exerciseId.'&num='.$questionNum.'&exerciseType='.$exerciseType.'&'.api_get_cidreq().'";
         </script>';
 }
-
 echo '</div>';

+ 2 - 2
main/exercise/fill_blanks.class.php

@@ -15,8 +15,8 @@ class FillBlanks extends Question
     const FILL_THE_BLANK_MENU = 1;
     const FILL_THE_BLANK_SEVERAL_ANSWER = 2;
 
-    public static $typePicture = 'fill_in_blanks.png';
-    public static $explanationLangVar = 'FillBlanks';
+    public $typePicture = 'fill_in_blanks.png';
+    public $explanationLangVar = 'FillBlanks';
 
     /**
      * Constructor.

+ 2 - 2
main/exercise/freeanswer.class.php

@@ -12,8 +12,8 @@
  */
 class FreeAnswer extends Question
 {
-    public static $typePicture = 'open_answer.png';
-    public static $explanationLangVar = 'FreeAnswer';
+    public $typePicture = 'open_answer.png';
+    public $explanationLangVar = 'FreeAnswer';
 
     /**
      * Constructor.

+ 2 - 2
main/exercise/global_multiple_answer.class.php

@@ -8,8 +8,8 @@ use ChamiloSession as Session;
  */
 class GlobalMultipleAnswer extends Question
 {
-    public static $typePicture = 'mcmagl.png';
-    public static $explanationLangVar = 'GlobalMultipleAnswer';
+    public $typePicture = 'mcmagl.png';
+    public $explanationLangVar = 'GlobalMultipleAnswer';
 
     /**
      * GlobalMultipleAnswer constructor.

+ 2 - 49
main/exercise/hotspot.class.php

@@ -14,8 +14,8 @@
  */
 class HotSpot extends Question
 {
-    public static $typePicture = 'hotspot.png';
-    public static $explanationLangVar = 'HotSpot';
+    public $typePicture = 'hotspot.png';
+    public $explanationLangVar = 'HotSpot';
 
     /**
      * HotSpot constructor.
@@ -105,50 +105,3 @@ class HotSpot extends Question
         // nothing
     }
 }
-
-/**
- * Class HotSpotDelineation.
- */
-class HotSpotDelineation extends HotSpot
-{
-    public static $typePicture = 'hotspot-delineation.png';
-    public static $explanationLangVar = 'HotspotDelineation';
-
-    /**
-     * HotSpotDelineation constructor.
-     */
-    public function __construct()
-    {
-        parent::__construct();
-        $this->type = HOT_SPOT_DELINEATION;
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function createForm(&$form, $exercise)
-    {
-        parent::createForm($form, $exercise);
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function processCreation($form, $exercise)
-    {
-        parent::processCreation($form, $exercise);
-    }
-
-    public function createAnswersForm($form)
-    {
-        parent::createAnswersForm($form);
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function processAnswersCreation($form, $exercise)
-    {
-        parent::processAnswersCreation($form, $exercise);
-    }
-}

+ 2 - 2
main/exercise/matching.class.php

@@ -15,8 +15,8 @@
  */
 class Matching extends Question
 {
-    public static $typePicture = 'matching.png';
-    public static $explanationLangVar = 'Matching';
+    public $typePicture = 'matching.png';
+    public $explanationLangVar = 'Matching';
 
     /**
      * Constructor.

+ 2 - 2
main/exercise/multiple_answer.class.php

@@ -15,8 +15,8 @@ use ChamiloSession as Session;
  */
 class MultipleAnswer extends Question
 {
-    public static $typePicture = 'mcma.png';
-    public static $explanationLangVar = 'MultipleSelect';
+    public $typePicture = 'mcma.png';
+    public $explanationLangVar = 'MultipleSelect';
 
     /**
      * Constructor.

+ 2 - 2
main/exercise/multiple_answer_combination.class.php

@@ -16,8 +16,8 @@ use ChamiloSession as Session;
  */
 class MultipleAnswerCombination extends Question
 {
-    public static $typePicture = 'mcmac.png';
-    public static $explanationLangVar = 'MultipleSelectCombination';
+    public $typePicture = 'mcmac.png';
+    public $explanationLangVar = 'MultipleSelectCombination';
 
     /**
      * Constructor.

+ 2 - 2
main/exercise/multiple_answer_combination_true_false.class.php

@@ -13,8 +13,8 @@
  */
 class MultipleAnswerCombinationTrueFalse extends MultipleAnswerCombination
 {
-    public static $typePicture = 'mcmaco.png';
-    public static $explanationLangVar = 'MultipleAnswerCombinationTrueFalse';
+    public $typePicture = 'mcmaco.png';
+    public $explanationLangVar = 'MultipleAnswerCombinationTrueFalse';
     public $options;
 
     /**

+ 2 - 2
main/exercise/multiple_answer_true_false.class.php

@@ -14,8 +14,8 @@ use ChamiloSession as Session;
  */
 class MultipleAnswerTrueFalse extends Question
 {
-    public static $typePicture = 'mcmao.png';
-    public static $explanationLangVar = 'MultipleAnswerTrueFalse';
+    public $typePicture = 'mcmao.png';
+    public $explanationLangVar = 'MultipleAnswerTrueFalse';
     public $options;
 
     /**

+ 2 - 2
main/exercise/oral_expression.class.php

@@ -12,8 +12,8 @@
  */
 class OralExpression extends Question
 {
-    public static $typePicture = 'audio_question.png';
-    public static $explanationLangVar = 'OralExpression';
+    public $typePicture = 'audio_question.png';
+    public $explanationLangVar = 'OralExpression';
     public $available_extensions = ['wav', 'ogg'];
     private $sessionId;
     private $userId;

+ 40 - 34
main/exercise/question.class.php

@@ -33,8 +33,8 @@ abstract class Question
     public $isContent;
     public $course;
     public $feedback;
-    public static $typePicture = 'new_question.png';
-    public static $explanationLangVar = '';
+    public $typePicture = 'new_question.png';
+    public $explanationLangVar = '';
     public $question_table_class = 'table table-striped';
     public $questionTypeWithFeedback;
     public $extra;
@@ -48,7 +48,7 @@ abstract class Question
         FREE_ANSWER => ['freeanswer.class.php', 'FreeAnswer'],
         ORAL_EXPRESSION => ['oral_expression.class.php', 'OralExpression'],
         HOT_SPOT => ['hotspot.class.php', 'HotSpot'],
-        HOT_SPOT_DELINEATION => ['hotspot.class.php', 'HotspotDelineation'],
+        HOT_SPOT_DELINEATION => ['HotSpotDelineation.php', 'HotSpotDelineation'],
         MULTIPLE_ANSWER_COMBINATION => ['multiple_answer_combination.class.php', 'MultipleAnswerCombination'],
         UNIQUE_ANSWER_NO_OPTION => ['unique_answer_no_option.class.php', 'UniqueAnswerNoOption'],
         MULTIPLE_ANSWER_TRUE_FALSE => ['multiple_answer_true_false.class.php', 'MultipleAnswerTrueFalse'],
@@ -1547,12 +1547,13 @@ abstract class Question
     /**
      * @return array
      */
-    public static function get_question_type_list()
+    public static function getQuestionTypeList()
     {
         if (api_get_setting('enable_record_audio') !== 'true') {
             self::$questionTypes[ORAL_EXPRESSION] = null;
             unset(self::$questionTypes[ORAL_EXPRESSION]);
         }
+
         if (api_get_setting('enable_quiz_scenario') !== 'true') {
             self::$questionTypes[HOT_SPOT_DELINEATION] = null;
             unset(self::$questionTypes[HOT_SPOT_DELINEATION]);
@@ -1814,33 +1815,41 @@ abstract class Question
         $exerciseId = $objExercise->id;
 
         // 1. by default we show all the question types
-        $question_type_custom_list = self::get_question_type_list();
+        $questionTypeList = self::getQuestionTypeList();
 
         if (!isset($feedbackType)) {
             $feedbackType = 0;
         }
 
-        if (in_array($feedbackType, [EXERCISE_FEEDBACK_TYPE_DIRECT, EXERCISE_FEEDBACK_TYPE_POPUP])) {
-            //2. but if it is a feedback DIRECT we only show the UNIQUE_ANSWER type that is currently available
-            $question_type_custom_list = [
-                UNIQUE_ANSWER => self::$questionTypes[UNIQUE_ANSWER],
-                HOT_SPOT_DELINEATION => self::$questionTypes[HOT_SPOT_DELINEATION],
-            ];
-        } else {
-            unset($question_type_custom_list[HOT_SPOT_DELINEATION]);
+        switch ($feedbackType) {
+            case EXERCISE_FEEDBACK_TYPE_DIRECT:
+                $questionTypeList = [
+                    UNIQUE_ANSWER => self::$questionTypes[UNIQUE_ANSWER],
+                    HOT_SPOT_DELINEATION => self::$questionTypes[HOT_SPOT_DELINEATION],
+                ];
+                break;
+            case EXERCISE_FEEDBACK_TYPE_POPUP:
+                $questionTypeList = [
+                    UNIQUE_ANSWER => self::$questionTypes[UNIQUE_ANSWER],
+                    MULTIPLE_ANSWER => self::$questionTypes[MULTIPLE_ANSWER],
+                    DRAGGABLE => self::$questionTypes[DRAGGABLE],
+                    HOT_SPOT_DELINEATION => self::$questionTypes[HOT_SPOT_DELINEATION],
+                    CALCULATED_ANSWER => self::$questionTypes[CALCULATED_ANSWER],
+                ];
+                break;
+            default:
+                unset($questionTypeList[HOT_SPOT_DELINEATION]);
+                break;
         }
 
         echo '<div class="panel panel-default">';
         echo '<div class="panel-body">';
         echo '<ul class="question_menu">';
-        foreach ($question_type_custom_list as $i => $a_type) {
-            // @todo remove require_once classes are already loaded using composer
-            // include the class of the type
-            require_once $a_type[0];
-            // get the picture of the type and the langvar which describes it
-            $img = $explanation = '';
-            eval('$img = '.$a_type[1].'::$typePicture;');
-            eval('$explanation = get_lang('.$a_type[1].'::$explanationLangVar);');
+        foreach ($questionTypeList as $i => $type) {
+            /** @var Question $type */
+            $type = new $type[1];
+            $img = $type->getTypePicture();
+            $explanation = get_lang($type->getExplanation());
             echo '<li>';
             echo '<div class="icon-image">';
             $icon = '<a href="admin.php?'.api_get_cidreq().'&newQuestion=yes&answerType='.$i.'">'.
@@ -1853,7 +1862,6 @@ abstract class Question
                     $icon = Display::return_icon($img, $explanation, null, ICON_SIZE_BIG);
                 }
             }
-
             echo $icon;
             echo '</div>';
             echo '</li>';
@@ -2198,26 +2206,24 @@ abstract class Question
     }
 
     /**
-     * @return array the image filename of the question type
+     * @return string
      */
-    public function get_type_icon_html()
+    public function getTypePicture()
     {
-        $type = $this->selectType();
-        $tabQuestionList = self::get_question_type_list(); // [0]=file to include [1]=type name
-
-        require_once $tabQuestionList[$type][0];
-
-        $img = $explanation = null;
-        eval('$img = '.$tabQuestionList[$type][1].'::$typePicture;');
-        eval('$explanation = get_lang('.$tabQuestionList[$type][1].'::$explanationLangVar);');
+        return $this->typePicture;
+    }
 
-        return [$img, $explanation];
+    /**
+     * @return string
+     */
+    public function getExplanation()
+    {
+        return $this->explanationLangVar;
     }
 
     /**
      * Get course medias.
      *
-     * @param int course id
      * @param int $course_id
      *
      * @return array

+ 1 - 1
main/exercise/question_admin.inc.php

@@ -32,7 +32,7 @@ if (is_object($objQuestion)) {
         $type = $_REQUEST['answerType'];
     }
 
-    $typesInformation = Question::get_question_type_list();
+    $typesInformation = Question::getQuestionTypeList();
     $form_title_extra = isset($typesInformation[$type][1]) ? get_lang($typesInformation[$type][1]) : null;
 
     $code = '';

+ 2 - 2
main/exercise/question_create.php

@@ -31,7 +31,7 @@ $form = new FormValidator('add_question', 'post', api_get_self().'?'.api_get_cid
 // form title
 $form->addElement('header', '', get_lang('AddQuestionToExercise'));
 
-$question_list = Question::get_question_type_list();
+$question_list = Question::getQuestionTypeList();
 $question_list_options = [];
 foreach ($question_list as $key => $value) {
     $question_list_options[$key] = addslashes(get_lang($value[1]));
@@ -117,7 +117,7 @@ if ($form->validate()) {
 
 function check_question_type($parameter)
 {
-    $question_list = Question::get_question_type_list();
+    $question_list = Question::getQuestionTypeList();
     foreach ($question_list as $key => $value) {
         $valid_question_types[] = $key;
     }

+ 9 - 3
main/exercise/question_list_admin.inc.php

@@ -59,12 +59,12 @@ $ajax_url = api_get_path(WEB_AJAX_PATH).'exercise.ajax.php?'.api_get_cidreq().'&
             $("#dialog-confirm").dialog({
                 modal: true,
                 buttons: {
-                    "<?php echo get_lang("Yes"); ?>": function () {
+                    "<?php echo get_lang('Yes'); ?>": function () {
                         location.href = targetUrl;
                         $(this).dialog("close");
 
                     },
-                    "<?php echo get_lang("No"); ?>": function () {
+                    "<?php echo get_lang('No'); ?>": function () {
                         $(this).dialog("close");
                     }
                 }
@@ -223,6 +223,10 @@ if (!$inATest) {
                 /** @var Question $objQuestionTmp */
                 $objQuestionTmp = Question::read($id);
 
+                if (empty($objQuestionTmp)) {
+                    continue;
+                }
+
                 $clone_link = Display::url(
                     Display::return_icon(
                         'cd.png',
@@ -303,7 +307,9 @@ if (!$inATest) {
                     </a>';
 
                 // Question type
-                list($typeImg, $typeExpl) = $objQuestionTmp->get_type_icon_html();
+                $typeImg = $objQuestionTmp->getTypePicture();
+                $typeExpl = $objQuestionTmp->getExplanation();
+
                 $questionType = Display::return_icon($typeImg, $typeExpl);
 
                 // Question category

+ 6 - 4
main/exercise/question_pool.php

@@ -472,7 +472,7 @@ $select_difficulty_html = Display::select(
 echo Display::form_row(get_lang('Difficulty'), $select_difficulty_html);
 
 // Answer type
-$question_list = Question::get_question_type_list();
+$question_list = Question::getQuestionTypeList();
 
 $new_question_list = [];
 $new_question_list['-1'] = get_lang('All');
@@ -1177,10 +1177,12 @@ function get_action_icon_for_question(
 function get_question_type_for_question($in_selectedcourse, $in_questionid)
 {
     $courseInfo = api_get_course_info_by_id($in_selectedcourse);
-    $myObjQuestion = Question::read($in_questionid, $courseInfo);
+    $question = Question::read($in_questionid, $courseInfo);
     $questionType = null;
-    if (!empty($myObjQuestion)) {
-        list($typeImg, $typeExpl) = $myObjQuestion->get_type_icon_html();
+    if (!empty($question)) {
+        $typeImg = $question->getTypePicture();
+        $typeExpl = $question->getExplanation();
+
         $questionType = Display::tag('div', Display::return_icon($typeImg, $typeExpl, [], 32), []);
     }
 

+ 2 - 2
main/exercise/unique_answer.class.php

@@ -18,8 +18,8 @@ use ChamiloSession as Session;
  */
 class UniqueAnswer extends Question
 {
-    public static $typePicture = 'mcua.png';
-    public static $explanationLangVar = 'UniqueSelect';
+    public $typePicture = 'mcua.png';
+    public $explanationLangVar = 'UniqueSelect';
 
     /**
      * Constructor.

+ 2 - 2
main/exercise/unique_answer_no_option.class.php

@@ -15,8 +15,8 @@ use ChamiloSession as Session;
  */
 class UniqueAnswerNoOption extends Question
 {
-    public static $typePicture = 'mcuao.png';
-    public static $explanationLangVar = 'UniqueAnswerNoOption';
+    public $typePicture = 'mcuao.png';
+    public $explanationLangVar = 'UniqueAnswerNoOption';
 
     /**
      * Constructor.