Fix "Multiple answer true/false/don't know" question CRUD

1.10.x
Julio Montoya 11 years ago
parent c169d7fcac
commit 21318bb128
  1. 66
      main/exercice/answer.class.php
  2. 178
      main/exercice/exercise.class.php
  3. 15
      main/exercice/exercise_show.php
  4. 38
      main/exercice/multiple_answer_true_false.class.php
  5. 118
      main/exercice/question_admin.inc.php
  6. 6
      main/inc/lib/exercise.lib.php

@ -115,22 +115,22 @@ class Answer
$result = Database::query($sql);
$i=1;
// while a record is found
while ($object = Database::fetch_object($result)) {
$this->id[$i] = $object->id;
$this->answer[$i] = $object->answer;
$this->correct[$i] = $object->correct;
$this->comment[$i] = $object->comment;
$this->weighting[$i] = $object->ponderation;
$this->position[$i] = $object->position;
$this->hotspot_coordinates[$i] = $object->hotspot_coordinates;
$this->hotspot_type[$i] = $object->hotspot_type;
$this->destination[$i] = $object->destination;
$this->autoId[$i] = $object->id_auto;
$i++;
}
$this->nbrAnswers = $i-1;
}
// while a record is found
while ($object = Database::fetch_object($result)) {
$this->id[$i] = $object->id;
$this->answer[$i] = $object->answer;
$this->correct[$i] = $object->correct;
$this->comment[$i] = $object->comment;
$this->weighting[$i] = $object->ponderation;
$this->position[$i] = $object->position;
$this->hotspot_coordinates[$i] = $object->hotspot_coordinates;
$this->hotspot_type[$i] = $object->hotspot_type;
$this->destination[$i] = $object->destination;
$this->autoId[$i] = $object->id_auto;
$i++;
}
$this->nbrAnswers = $i-1;
}
/**
* returns all answer ids from this question Id
@ -178,9 +178,10 @@ class Answer
$TBL_ANSWER = Database::get_course_table(TABLE_QUIZ_ANSWER);
$TBL_QUIZ = Database::get_course_table(TABLE_QUIZ_QUESTION);
$questionId=intval($this->questionId);
$questionId = intval($this->questionId);
$sql = "SELECT type FROM $TBL_QUIZ WHERE c_id = {$this->course_id} AND id = $questionId";
$sql = "SELECT type FROM $TBL_QUIZ
WHERE c_id = {$this->course_id} AND id = $questionId";
$result_question = Database::query($sql);
$question_type = Database::fetch_array($result_question);
@ -532,6 +533,7 @@ class Answer
'hotspot_coordinates' => $hotspot_coordinates,
'hotspot_type' => $hotspot_type,
];
Database::update($answerTable, $params, ['id_auto = ?' => $autoId]);
}
@ -582,6 +584,7 @@ class Answer
// https://support.chamilo.org/issues/6558
// function updateAnswers already escape_string, error if we do it twice.
// Feed function updateAnswers with none escaped strings
$this->updateAnswers(
$autoId,
$this->new_answer[$i],
@ -596,26 +599,31 @@ class Answer
}
$answerList[$i] = $autoId;
if ($correct) {
$correctList[$autoId] = array('id' => $i, 'correct' => $correct);
$correctList[$autoId] = true;
}
}
if (!empty($correctList)) {
foreach ($correctList as $autoId => $data) {
$correct = $data['correct'];
$questionType = self::getQuestionType();
if (isset($answerList[$correct])) {
$correct = $answerList[$correct];
}
if ($questionType == MATCHING) {
$sql = "UPDATE $answerTable
SET correct = $correct
if (!empty($correctList)) {
foreach ($correctList as $autoId => $status) {
/*$correct = $data['correct'];
if (isset($answerList[$correct])) {
$correct = $answerList[$correct];
}*/
$sql = "UPDATE $answerTable
SET correct = $autoId
WHERE
id_auto = $autoId
";
Database::query($sql);
Database::query($sql);
}
}
}

@ -2283,9 +2283,9 @@ class Exercise
$user_answer = '';
// Get answer list for matching
$sql_answer = 'SELECT id_auto, id, answer FROM '.$table_ans.'
WHERE c_id = '.$course_id.' AND question_id = "'.$questionId.'"';
$res_answer = Database::query($sql_answer);
$sql = "SELECT id_auto, id, answer FROM $table_ans
WHERE c_id = $course_id AND question_id = $questionId";
$res_answer = Database::query($sql);
$answerMatching = array();
while ($real_answer = Database::fetch_array($res_answer)) {
@ -2440,15 +2440,17 @@ class Exercise
break;
case MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE:
if ($from_database) {
$queryans = "SELECT answer FROM ".$TBL_TRACK_ATTEMPT."
WHERE exe_id = ".$exeId." AND question_id= ".$questionId;
$resultans = Database::query($queryans);
$sql = "SELECT answer FROM ".$TBL_TRACK_ATTEMPT."
WHERE exe_id = $exeId AND question_id= ".$questionId;
$resultans = Database::query($sql);
while ($row = Database::fetch_array($resultans)) {
$ind = $row['answer'];
$result = explode(':',$ind);
$my_answer_id = $result[0];
$option = $result[1];
$choice[$my_answer_id] = $option;
if (isset($result[0])) {
$my_answer_id = $result[0];
$option = $result[1];
$choice[$my_answer_id] = $option;
}
}
$studentChoice = $choice[$answerAutoId];
@ -2472,16 +2474,17 @@ class Exercise
break;
case MULTIPLE_ANSWER_COMBINATION:
if ($from_database) {
$queryans = "SELECT answer FROM ".$TBL_TRACK_ATTEMPT."
WHERE exe_id = '".$exeId."' and question_id= '".$questionId."'";
$resultans = Database::query($queryans);
$sql = "SELECT answer FROM $TBL_TRACK_ATTEMPT
WHERE exe_id = $exeId AND question_id= $questionId";
$resultans = Database::query($sql);
while ($row = Database::fetch_array($resultans)) {
$ind = $row['answer'];
$choice[$ind] = 1;
}
$studentChoice = isset($choice[$answerAutoId]) ? $choice[$answerAutoId] : null;
if ($answerCorrect == 1) {
if ($answerCorrect == $answerAutoId) {
if ($studentChoice) {
$real_answers[$answerId] = true;
} else {
@ -2591,155 +2594,6 @@ class Exercise
}
$answer = FillBlanks::getAnswerInStudentAttempt($listCorrectAnswers);
// the question is encoded like this
// [A] B [C] D [E] F::10,10,10@1
// number 1 before the "@" means that is a switchable fill in blank question
// [A] B [C] D [E] F::10,10,10@ or [A] B [C] D [E] F::10,10,10
// means that is a normal fill blank question
// first we explode the "::"
/*
$pre_array = explode('::', $answer);
// is switchable fill blank or not
$last = count($pre_array) - 1;
$is_set_switchable = explode('@', $pre_array[$last]);
$switchable_answer_set = false;
if (isset ($is_set_switchable[1]) && $is_set_switchable[1] == 1) {
$switchable_answer_set = true;
}
$answer = '';
for ($k = 0; $k < $last; $k++) {
$answer .= $pre_array[$k];
}
// splits weightings that are joined with a comma
$answerWeighting = explode(',', $is_set_switchable[0]);
// we save the answer because it will be modified
$temp = $answer;
$answer = '';
$j = 0;
//initialise answer tags
$user_tags = $correct_tags = $real_text = array();
// the loop will stop at the end of the text
while (1) {
// quits the loop if there are no more blanks (detect '[')
if (($pos = api_strpos($temp, '[')) === false) {
// adds the end of the text
$answer = $temp;
$real_text[] = $answer;
break; //no more "blanks", quit the loop
}
// adds the piece of text that is before the blank
// and ends with '[' into a general storage array
$real_text[] = api_substr($temp, 0, $pos +1);
$answer .= api_substr($temp, 0, $pos +1);
//take the string remaining (after the last "[" we found)
$temp = api_substr($temp, $pos +1);
// quit the loop if there are no more blanks, and update $pos to the position of next ']'
if (($pos = api_strpos($temp, ']')) === false) {
// adds the end of the text
$answer .= $temp;
break;
}
if ($from_database) {
$queryfill = "SELECT answer FROM ".$TBL_TRACK_ATTEMPT."
WHERE
exe_id = '".$exeId."' AND
question_id= ".intval($questionId)."";
$resfill = Database::query($queryfill);
$str = Database::result($resfill, 0, 'answer');
api_preg_match_all('#\[([^[]*)\]#', $str, $arr);
$str = str_replace('\r\n', '', $str);
$choice = $arr[1];
if (isset($choice[$j])) {
$tmp = api_strrpos($choice[$j], ' / ');
$choice[$j] = api_substr($choice[$j], 0, $tmp);
$choice[$j] = trim($choice[$j]);
// Needed to let characters ' and " to work as part of an answer
$choice[$j] = stripslashes($choice[$j]);
} else {
$choice[$j] = null;
}
} else {
// This value is the user input, not escaped while correct answer is escaped by fckeditor
// Works with cyrillic alphabet and when using ">" chars
$choice[$j] = htmlentities(api_utf8_encode(trim($choice[$j])));
}
$user_tags[] = $choice[$j];
//put the contents of the [] answer tag into correct_tags[]
$correct_tags[] = api_substr($temp, 0, $pos);
$j++;
$temp = api_substr($temp, $pos +1);
}
$answer = '';
$real_correct_tags = $correct_tags;
$chosen_list = array();
for ($i = 0; $i < count($real_correct_tags); $i++) {
if ($i == 0) {
$answer .= $real_text[0];
}
if (!$switchable_answer_set) {
// Needed to parse ' and " characters
$user_tags[$i] = stripslashes($user_tags[$i]);
if ($correct_tags[$i] == $user_tags[$i]) {
// gives the related weighting to the student
$questionScore += $answerWeighting[$i];
// increments total score
$totalScore += $answerWeighting[$i];
// adds the word in green at the end of the string
$answer .= $correct_tags[$i];
} elseif (!empty($user_tags[$i])) {
// else if the word entered by the student IS NOT the same as the one defined by the professor
// adds the word in red at the end of the string, and strikes it
$answer .= '<font color="red"><s>' . $user_tags[$i] . '</s></font>';
} else {
// adds a tabulation if no word has been typed by the student
$answer .= ''; // remove &nbsp; that causes issue
}
} else {
// switchable fill in the blanks
if (in_array($user_tags[$i], $correct_tags)) {
$chosen_list[] = $user_tags[$i];
$correct_tags = array_diff($correct_tags, $chosen_list);
// gives the related weighting to the student
$questionScore += $answerWeighting[$i];
// increments total score
$totalScore += $answerWeighting[$i];
// adds the word in green at the end of the string
$answer .= $user_tags[$i];
} elseif (!empty ($user_tags[$i])) {
// else if the word entered by the student IS NOT the same as the one defined by the professor
// adds the word in red at the end of the string, and strikes it
$answer .= '<font color="red"><s>' . $user_tags[$i] . '</s></font>';
} else {
// adds a tabulation if no word has been typed by the student
$answer .= ''; // remove &nbsp; that causes issue
}
}
// adds the correct word, followed by ] to close the blank
$answer .= ' / <font color="green"><b>' . $real_correct_tags[$i] . '</b></font>]';
if (isset($real_text[$i +1])) {
$answer .= $real_text[$i + 1];
}
}*/
break;
// for calculated answer
case CALCULATED_ANSWER:

@ -12,8 +12,6 @@
*
*/
// name of the language file that needs to be included
use ChamiloSession as Session;
require_once '../inc/global.inc.php';
@ -166,8 +164,8 @@ function getFCK(vals,marksid) {
}
</script>
<?php
$show_results = true;
$show_only_total_score = false;
$show_results = true;
$show_only_total_score = false;
// Avoiding the "Score 0/0" message when the exe_id is not set
if (!empty($track_exercise_info)) {
@ -232,10 +230,10 @@ $arrans = array();
$user_restriction = $is_allowedToEdit ? '' : "AND user_id=".intval($student_id)." ";
$sql = "SELECT attempts.question_id, answer
FROM ".$TBL_TRACK_ATTEMPT." as attempts
FROM $TBL_TRACK_ATTEMPT as attempts
INNER JOIN ".$TBL_TRACK_EXERCISES." AS stats_exercises
ON stats_exercises.exe_id=attempts.exe_id
INNER JOIN ".$TBL_EXERCISE_QUESTION." AS quizz_rel_questions
INNER JOIN $TBL_EXERCISE_QUESTION AS quizz_rel_questions
ON
quizz_rel_questions.exercice_id=stats_exercises.exe_exo_id AND
quizz_rel_questions.question_id = attempts.question_id AND
@ -244,7 +242,8 @@ $sql = "SELECT attempts.question_id, answer
ON
questions.id=quizz_rel_questions.question_id AND
questions.c_id = ".api_get_course_int_id()."
WHERE attempts.exe_id = ".intval($id)." $user_restriction
WHERE
attempts.exe_id = ".intval($id)." $user_restriction
GROUP BY quizz_rel_questions.question_order, attempts.question_id";
$result = Database::query($sql);
@ -284,7 +283,7 @@ if (!empty($end_of_message) && ($origin == 'learnpath')) {
$total_weighting = 0;
foreach ($questionList as $questionId) {
$objQuestionTmp = Question::read($questionId);
$total_weighting +=$objQuestionTmp->selectWeighting();
$total_weighting +=$objQuestionTmp->selectWeighting();
}
$counter = 1;

@ -82,7 +82,7 @@ class MultipleAnswerTrueFalse extends Question
}
// Can be more options
$option_data = Question::readQuestionOption($this->id, $course_id);
$optionData = Question::readQuestionOption($this->id, $course_id);
for ($i = 1; $i <= $nb_answers; ++$i) {
$form->addHtml('<tr>');
@ -120,8 +120,8 @@ class MultipleAnswerTrueFalse extends Question
$defaults['correct[' . $i . ']'] = $correct;
$j = 1;
if (!empty($option_data)) {
foreach ($option_data as $id => $data) {
if (!empty($optionData)) {
foreach ($optionData as $id => $data) {
$form->addElement('radio', 'correct[' . $i . ']', null, null, $id);
$j++;
if ($j == 3) {
@ -212,7 +212,6 @@ class MultipleAnswerTrueFalse extends Question
if (!empty($this->extra)) {
$scores = explode(':', $this->extra);
if (!empty($scores)) {
for ($i = 1; $i <= 3; $i++) {
$defaults['option[' . $i . ']'] = $scores[$i - 1];
@ -231,8 +230,6 @@ class MultipleAnswerTrueFalse extends Question
$form->addGroup($buttonGroup);
}
$defaults['correct'] = $correct;
if (!empty($this->id)) {
$form->setDefaults($defaults);
} else {
@ -250,19 +247,19 @@ class MultipleAnswerTrueFalse extends Question
public function processAnswersCreation($form)
{
$questionWeighting = $nbrGoodAnswers = 0;
$objAnswer = new Answer($this->id);
$nb_answers = $form->getSubmitValue('nb_answers');
$options_count = $form->getSubmitValue('options_count');
$course_id = api_get_course_int_id();
$objAnswer = new Answer($this->id);
$nb_answers = $form->getSubmitValue('nb_answers');
//$options_count = $form->getSubmitValue('options_count');
$course_id = api_get_course_int_id();
$correct = array();
$options = Question::readQuestionOption($this->id, $course_id);
if (!empty($options)) {
foreach ($options as $option_data) {
$id = $option_data['id'];
unset($option_data['id']);
Question::updateQuestionOption($id, $option_data, $course_id);
foreach ($options as $optionData) {
$id = $optionData['id'];
unset($optionData['id']);
Question::updateQuestionOption($id, $optionData, $course_id);
}
} else {
for ($i=1 ; $i <= 3 ; $i++) {
@ -282,7 +279,7 @@ class MultipleAnswerTrueFalse extends Question
$new_options = Question::readQuestionOption($this->id, $course_id);
$sorted_by_position = array();
foreach($new_options as $item) {
foreach ($new_options as $item) {
$sorted_by_position[$item['position']] = $item;
}
@ -294,18 +291,19 @@ class MultipleAnswerTrueFalse extends Question
$score = trim($form -> getSubmitValue('option['.$i.']'));
$extra_values[]= $score;
}
$this->setExtra(implode(':',$extra_values));
$this->setExtra(implode(':', $extra_values));
for ($i=1 ; $i <= $nb_answers ; $i++) {
$answer = trim($form -> getSubmitValue('answer['.$i.']'));
$comment = trim($form -> getSubmitValue('comment['.$i.']'));
$goodAnswer = trim($form -> getSubmitValue('correct['.$i.']'));
for ($i = 1; $i <= $nb_answers; $i++) {
$answer = trim($form->getSubmitValue('answer['.$i.']'));
$comment = trim($form->getSubmitValue('comment['.$i.']'));
$goodAnswer = trim($form->getSubmitValue('correct['.$i.']'));
if (empty($options)) {
//If this is the first time that the question is created when
// change the default values from the form 1 and 2 by the correct "option id" registered
$goodAnswer = $sorted_by_position[$goodAnswer]['id'];
}
$questionWeighting += $extra_values[0]; //By default 0 has the correct answers
$objAnswer->createAnswer($answer, $goodAnswer, $comment,'',$i);
}

@ -11,77 +11,77 @@
*/
if (isset($_GET['editQuestion'])) {
$objQuestion = Question::read ($_GET['editQuestion']);
$action = api_get_self()."?".api_get_cidreq()."&myid=1&modifyQuestion=".$modifyQuestion."&editQuestion=".$objQuestion->id;
$objQuestion = Question::read ($_GET['editQuestion']);
$action = api_get_self()."?".api_get_cidreq()."&myid=1&modifyQuestion=".$modifyQuestion."&editQuestion=".$objQuestion->id;
} else {
$objQuestion = Question :: getInstance($_REQUEST['answerType']);
$action = api_get_self()."?".api_get_cidreq()."&modifyQuestion=".$modifyQuestion."&newQuestion=".$newQuestion;
$objQuestion = Question :: getInstance($_REQUEST['answerType']);
$action = api_get_self()."?".api_get_cidreq()."&modifyQuestion=".$modifyQuestion."&newQuestion=".$newQuestion;
}
if (is_object($objQuestion)) {
// FORM CREATION
$form = new FormValidator('question_admin_form','post', $action);
if (isset($_GET['editQuestion'])) {
$class = "btn btn-default";
$text = get_lang('ModifyQuestion');
$type = isset($_GET['type']) ? Security::remove_XSS($_GET['type']) : null;
} else {
$class = "btn btn-default";
$text = get_lang('AddQuestionToExercise');
$type = $_REQUEST['answerType'];
}
// FORM CREATION
$form = new FormValidator('question_admin_form','post', $action);
if (isset($_GET['editQuestion'])) {
$class = "btn btn-default";
$text = get_lang('ModifyQuestion');
$type = isset($_GET['type']) ? Security::remove_XSS($_GET['type']) : null;
} else {
$class = "btn btn-default";
$text = get_lang('AddQuestionToExercise');
$type = $_REQUEST['answerType'];
}
$typesInformation = Question::get_question_type_list();
$form_title_extra = isset($typesInformation[$type][1]) ? get_lang($typesInformation[$type][1]) : null;
$typesInformation = Question::get_question_type_list();
$form_title_extra = isset($typesInformation[$type][1]) ? get_lang($typesInformation[$type][1]) : null;
// form title
$form->addElement('header', $text.': '.$form_title_extra);
// form title
$form->addElement('header', $text.': '.$form_title_extra);
// question form elements
$objQuestion->createForm($form);
// question form elements
$objQuestion->createForm($form);
// answer form elements
$objQuestion->createAnswersForm($form);
// answer form elements
$objQuestion->createAnswersForm($form);
// this variable $show_quiz_edition comes from admin.php blocks the exercise/quiz modifications
if ($objExercise->edit_exercise_in_lp == false) {
$form->freeze();
}
// this variable $show_quiz_edition comes from admin.php blocks the exercise/quiz modifications
if ($objExercise->edit_exercise_in_lp == false) {
$form->freeze();
}
// FORM VALIDATION
if (isset($_POST['submitQuestion']) && $form->validate()) {
// FORM VALIDATION
if (isset($_POST['submitQuestion']) && $form->validate()) {
// question
$objQuestion->processCreation($form, $objExercise);
// question
$objQuestion->processCreation($form, $objExercise);
// answers
$nb_answers = isset($nb_answers) ? $nb_answers : 0;
$objQuestion->processAnswersCreation($form, $nb_answers);
// answers
$nb_answers = isset($nb_answers) ? $nb_answers : 0;
$objQuestion->processAnswersCreation($form, $nb_answers);
// TODO: maybe here is the better place to index this tool, including answers text
// TODO: maybe here is the better place to index this tool, including answers text
// redirect
if ($objQuestion->type != HOT_SPOT && $objQuestion->type != HOT_SPOT_DELINEATION) {
if(isset($_GET['editQuestion'])) {
echo '<script type="text/javascript">window.location.href="admin.php?exerciseId='.$exerciseId.'&'.api_get_cidreq().'&message=ItemUpdated"</script>';
} else {
//New question
echo '<script type="text/javascript">window.location.href="admin.php?exerciseId='.$exerciseId.'&'.api_get_cidreq().'&message=ItemAdded"</script>';
}
} else {
echo '<script type="text/javascript">window.location.href="admin.php?exerciseId='.$exerciseId.'&hotspotadmin='.$objQuestion->id.'&'.api_get_cidreq().'"</script>';
}
} else {
if (isset($questionName)) {
echo '<h3>'.$questionName.'</h3>';
}
if (!empty($pictureName)) {
echo '<img src="../document/download.php?doc_url=%2Fimages%2F'.$pictureName.'" border="0">';
}
if(!empty($msgErr)) {
Display::display_normal_message($msgErr); //main API
}
// display the form
$form->display();
}
// redirect
if ($objQuestion->type != HOT_SPOT && $objQuestion->type != HOT_SPOT_DELINEATION) {
if(isset($_GET['editQuestion'])) {
echo '<script type="text/javascript">window.location.href="admin.php?exerciseId='.$exerciseId.'&'.api_get_cidreq().'&message=ItemUpdated"</script>';
} else {
//New question
echo '<script type="text/javascript">window.location.href="admin.php?exerciseId='.$exerciseId.'&'.api_get_cidreq().'&message=ItemAdded"</script>';
}
} else {
echo '<script type="text/javascript">window.location.href="admin.php?exerciseId='.$exerciseId.'&hotspotadmin='.$objQuestion->id.'&'.api_get_cidreq().'"</script>';
}
} else {
if (isset($questionName)) {
echo '<h3>'.$questionName.'</h3>';
}
if (!empty($pictureName)) {
echo '<img src="../document/download.php?doc_url=%2Fimages%2F'.$pictureName.'" border="0">';
}
if (!empty($msgErr)) {
Display::display_normal_message($msgErr);
}
// display the form
$form->display();
}
}

@ -324,7 +324,6 @@ HTML;
if ($answerType == UNIQUE_ANSWER_IMAGE) {
$attributes['style'] = 'display: none;';
$answer = '<div class="thumbnail">' . $answer . '</div>';
}
@ -506,7 +505,9 @@ HTML;
if (!empty($user_choice_array)) {
foreach ($user_choice_array as $item) {
$item = explode(':', $item);
$my_choice[$item[0]] = $item[1];
if (isset($item[1]) && isset($item[0])) {
$my_choice[$item[0]] = $item[1];
}
}
}
$answer = Security::remove_XSS($answer, STUDENT);
@ -3479,7 +3480,6 @@ HTML;
$counter = 1;
$total_score = $total_weight = 0;
$exercise_content = null;
// Hide results

Loading…
Cancel
Save