Add setting "allow_quiz_question_feedback" requires DB change

- ALTER TABLE c_quiz_question ADD COLUMN feedback text;

See BT#12611
pull/2487/head
jmontoyaa 9 years ago
parent f8434d72c3
commit 41c164230f
  1. 13
      main/exercise/Annotation.php
  2. 23
      main/exercise/Draggable.php
  3. 23
      main/exercise/MatchingDraggable.php
  4. 2
      main/exercise/ReadingComprehension.php
  5. 13
      main/exercise/UniqueAnswerImage.php
  6. 20
      main/exercise/admin.php
  7. 14
      main/exercise/calculated_answer.class.php
  8. 5
      main/exercise/exercise.class.php
  9. 2
      main/exercise/exercise_result.php
  10. 6
      main/exercise/exercise_show.php
  11. 7
      main/exercise/export/aiken/aiken_classes.php
  12. 1
      main/exercise/export/exercise_import.inc.php
  13. 9
      main/exercise/export/qti2/qti2_classes.php
  14. 10
      main/exercise/export/scorm/scorm_classes.php
  15. 18
      main/exercise/fill_blanks.class.php
  16. 11
      main/exercise/freeanswer.class.php
  17. 14
      main/exercise/global_multiple_answer.class.php
  18. 30
      main/exercise/hotspot.class.php
  19. 16
      main/exercise/matching.class.php
  20. 21
      main/exercise/multiple_answer.class.php
  21. 14
      main/exercise/multiple_answer_combination.class.php
  22. 37
      main/exercise/multiple_answer_true_false.class.php
  23. 16
      main/exercise/oral_expression.class.php
  24. 126
      main/exercise/question.class.php
  25. 13
      main/exercise/question_admin.inc.php
  26. 2
      main/exercise/result.php
  27. 24
      main/exercise/unique_answer.class.php
  28. 21
      main/exercise/unique_answer_no_option.class.php
  29. 15
      main/inc/lib/exercise.lib.php
  30. 2
      main/install/configuration.dist.php

@ -27,12 +27,11 @@ class Annotation extends Question
}
/**
* @param FormValidator $form
* @param int $fck_config
* @inheritdoc
*/
public function createForm(&$form, $fck_config = 0)
public function createForm(&$form, $exercise)
{
parent::createForm($form, $fck_config);
parent::createForm($form, $exercise);
$form->addElement(
'number',
@ -115,11 +114,11 @@ class Annotation extends Question
}
/**
* @param FormValidator $form
* @inheritdoc
*/
public function processAnswersCreation($form)
public function processAnswersCreation($form, $exercise)
{
$this->weighting = $form->getSubmitValue('weighting');
$this->save();
$this->save($exercise);
}
}

@ -29,9 +29,7 @@ class Draggable extends Question
$defaults = array();
$nb_matches = $nb_options = 2;
$matches = array();
$answer = null;
if ($form->isSubmitted()) {
$nb_matches = $form->getSubmitValue('nb_matches');
$nb_options = $form->getSubmitValue('nb_options');
@ -174,29 +172,24 @@ class Draggable extends Question
}
/**
* Abstract function which creates the form to create / edit the answers of the question
* @param FormValidator $form
* @inheritdoc
*/
public function processAnswersCreation($form)
public function processAnswersCreation($form, $exercise)
{
$this->extra = $form->exportValue('orientation');
$nb_matches = $form->getSubmitValue('nb_matches');
$this->weighting = 0;
$position = 0;
$objAnswer = new Answer($this->id);
// Insert the options
for ($i = 1; $i <= $nb_matches; ++$i) {
$position++;
$objAnswer->createAnswer($position, 0, '', 0, $position);
}
// Insert the answers
for ($i = 1; $i <= $nb_matches; ++$i) {
$position++;
$answer = $form->getSubmitValue('answer['.$i.']');
$matches = $form->getSubmitValue('matches['.$i.']');
$weighting = $form->getSubmitValue('weighting['.$i.']');
@ -211,19 +204,15 @@ class Draggable extends Question
}
$objAnswer->save();
$this->save();
$this->save($exercise);
}
/**
* Shows question title an description
* @param string $feedback_type
* @param int $counter
* @param float $score
* @return string
* @inheritdoc
*/
public function return_header($feedback_type = null, $counter = null, $score = null)
public function return_header($exercise, $counter = null, $score = null)
{
$header = parent::return_header($feedback_type, $counter, $score);
$header = parent::return_header($exercise, $counter, $score);
$header .= '<table class="'.$this->question_table_class.'">
<tr>
<th>' . get_lang('ElementList').'</th>

@ -17,7 +17,6 @@ class MatchingDraggable extends Question
public function __construct()
{
parent::__construct();
$this->type = MATCHING_DRAGGABLE;
$this->isContent = $this->getIsContent();
}
@ -30,10 +29,8 @@ class MatchingDraggable extends Question
$defaults = array();
$nb_matches = $nb_options = 2;
$matches = array();
$answer = null;
$counter = 1;
if (isset($this->id)) {
$answer = new Answer($this->id);
$answer->read();
@ -60,7 +57,7 @@ class MatchingDraggable extends Question
$nb_matches++;
$nb_options++;
}
} else if (!empty($this->id)) {
} elseif (!empty($this->id)) {
if (count($answer->nbrAnswers) > 0) {
$nb_matches = $nb_options = 0;
for ($i = 1; $i <= $answer->nbrAnswers; $i++) {
@ -224,16 +221,14 @@ class MatchingDraggable extends Question
}
/**
* Process the creation of answers
* @param FormValidator $form
* @inheritdoc
*/
public function processAnswersCreation($form)
public function processAnswersCreation($form, $exercise)
{
$nb_matches = $form->getSubmitValue('nb_matches');
$nb_options = $form->getSubmitValue('nb_options');
$this->weighting = 0;
$position = 0;
$objAnswer = new Answer($this->id);
// Insert the options
@ -260,19 +255,15 @@ class MatchingDraggable extends Question
);
}
$objAnswer->save();
$this->save();
$this->save($exercise);
}
/**
* Shows question title an description
* @param string $feedback_type
* @param int $counter
* @param float $score
* @return string The header HTML code
* @inheritdoc
*/
public function return_header($feedback_type = null, $counter = null, $score = null)
public function return_header($exercise, $counter = null, $score = null)
{
$header = parent::return_header($feedback_type, $counter, $score);
$header = parent::return_header($exercise, $counter, $score);
$header .= '<table class="'.$this->question_table_class.'">
<tr>
<th>' . get_lang('ElementList').'</th>

@ -136,7 +136,7 @@ class ReadingComprehension extends UniqueAnswer
/**
* @inheritdoc
*/
public function createForm(&$form)
public function createForm(&$form, $exercise)
{
// Categories
$tabCat = TestCategory::getCategoriesIdAndName();

@ -274,7 +274,10 @@ class UniqueAnswerImage extends UniqueAnswer
$form->setConstants(array('nb_answers' => $numberAnswers));
}
public function processAnswersCreation($form)
/**
* @inheritdoc
*/
public function processAnswersCreation($form, $exercise)
{
$questionWeighting = $nbrGoodAnswers = 0;
$correct = $form->getSubmitValue('correct');
@ -361,12 +364,6 @@ class UniqueAnswerImage extends UniqueAnswer
// sets the total weighting of the question
$this->updateWeighting($questionWeighting);
$this->save();
$this->save($exercise);
}
public function return_header($feedback_type = null, $counter = null, $score = null)
{
return parent::return_header($feedback_type, $counter, $score);
}
}

@ -292,9 +292,15 @@ if (!empty($gradebook) && $gradebook == 'view') {
$interbreadcrumb[] = array("url" => "exercise.php", "name" => get_lang('Exercises'));
if (isset($_GET['newQuestion']) || isset($_GET['editQuestion'])) {
$interbreadcrumb[] = ["url" => "admin.php?exerciseId=".$objExercise->id, "name" => $objExercise->selectTitle(true)];
$interbreadcrumb[] = [
"url" => "admin.php?exerciseId=".$objExercise->id,
"name" => $objExercise->selectTitle(true),
];
} else {
$interbreadcrumb[] = ["url" => "#", "name" => $objExercise->selectTitle(true)];
$interbreadcrumb[] = [
"url" => "#",
"name" => $objExercise->selectTitle(true),
];
}
// shows a link to go back to the question pool
@ -314,7 +320,6 @@ if ($modifyIn == 'thisExercise') {
}
}
$htmlHeadXtra[] = '<script>
function multiple_answer_true_false_onchange(variable) {
var result = variable.checked;
var id = variable.id;
@ -385,11 +390,10 @@ if ($inATest) {
Display::return_icon('settings.png', get_lang('ModifyExercise'), '', ICON_SIZE_MEDIUM).'</a>';
$maxScoreAllQuestions = 0;
//$questionList = $objExercise->getQuestionList();
$questionList = $objExercise->selectQuestionList(true, true);
if (!empty($questionList)) {
foreach ($questionList as $q) {
$question = Question::read($q);
foreach ($questionList as $questionItemId) {
$question = Question::read($questionItemId);
if ($question) {
$maxScoreAllQuestions += $question->selectWeighting();
}
@ -415,7 +419,7 @@ if ($inATest) {
}
echo '</div>';
} else if (isset($_GET['newQuestion'])) {
} elseif (isset($_GET['newQuestion'])) {
// we are in create a new question from question pool not in a test
echo '<div class="actions">';
echo '<a href="'.api_get_path(WEB_CODE_PATH).'exercise/admin.php?'.api_get_cidreq().'">'.
@ -466,7 +470,7 @@ if ($newQuestion || $editQuestion) {
if (isset($_GET['hotspotadmin'])) {
if (!is_object($objQuestion)) {
$objQuestion = Question :: read($_GET['hotspotadmin']);
$objQuestion = Question::read($_GET['hotspotadmin']);
}
if (!$objQuestion) {
api_not_allowed();

@ -183,10 +183,9 @@ class CalculatedAnswer extends Question
}
/**
* abstract function which creates the form to create / edit the answers of the question
* @param FormValidator $form
* @inheritdoc
*/
public function processAnswersCreation($form)
public function processAnswersCreation($form, $exercise)
{
if (!self::isAnswered()) {
$table = Database::get_course_table(TABLE_QUIZ_ANSWER);
@ -247,14 +246,11 @@ class CalculatedAnswer extends Question
}
/**
* @param null $feedback_type
* @param null $counter
* @param null $score
* @return null|string
* @inheritdoc
*/
public function return_header($feedback_type = null, $counter = null, $score = null)
public function return_header($exercise, $counter = null, $score = null)
{
$header = parent::return_header($feedback_type, $counter, $score);
$header = parent::return_header($exercise, $counter, $score);
$header .= '<table class="'.$this->question_table_class.'">
<tr>
<th>'.get_lang("Answer").'</th>

@ -73,6 +73,8 @@ class Exercise
public $emailAlert;
public $notifyUserByEmail = '';
public $sessionId = 0;
public $questionFeedbackEnabled = false;
public $questionTypeWithFeedback;
/**
* Constructor of the class
@ -115,6 +117,9 @@ class Exercise
}
$this->course_id = $course_info['real_id'];
$this->course = $course_info;
// ALTER TABLE c_quiz_question ADD COLUMN feedback text;
$this->questionFeedbackEnabled = api_get_configuration_value('allow_quiz_question_feedback');
}
/**

@ -177,7 +177,7 @@ $max_score = $objExercise->get_max_score();
echo Display::return_message(get_lang('Saved').'<br />', 'normal', false);
// Display and save questions
ExerciseLib::display_question_list_by_attempt(
ExerciseLib::displayQuestionListByAttempt(
$objExercise,
$exe_id,
true,

@ -850,7 +850,11 @@ foreach ($questionList as $questionId) {
if ($show_results) {
//Shows question title an description
$question_content .= $objQuestionTmp->return_header(null, $counter, $score);
$question_content .= $objQuestionTmp->return_header(
$objExercise,
$counter,
$score
);
}
$counter++;
$question_content .= $contents;

@ -31,12 +31,15 @@ class Aiken2Question extends Question
return $answer;
}
function createAnswersForm($form)
public function createAnswersForm($form)
{
return true;
}
function processAnswersCreation($form)
/**
* @inheritdoc
*/
public function processAnswersCreation($form, $exercise)
{
return true;
}

@ -178,6 +178,7 @@ function import_exercise($file)
$last_exercise_id = $exercise->selectId();
$courseId = api_get_course_int_id();
if (!empty($last_exercise_id)) {
//var_dump($exercise_info);exit;
// For each question found...
foreach ($exercise_info['question'] as $question_array) {
//2. Create question

@ -53,12 +53,15 @@ class Ims2Question extends Question
return $answer;
}
function createAnswersForm($form)
public function createAnswersForm($form)
{
return true;
}
function processAnswersCreation($form)
/**
* @inheritdoc
*/
public function processAnswersCreation($form, $exercise)
{
return true;
}
@ -234,7 +237,7 @@ class ImsAnswerMatching extends Answer
$i = 0;
if (is_array($this->rightList)) {
foreach ($this->rightList as $rightKey=>$rightElement) {
foreach ($this->rightList as $rightKey => $rightElement) {
$out .= '<simpleAssociableChoice identifier="right_'.$i.'" >
<![CDATA['.formatExerciseQtiTitle($rightElement['answer']).']]>
</simpleAssociableChoice>'. "\n";

@ -135,12 +135,18 @@ class ScormQuestion extends Question
return array($js, $html);
}
function createAnswersForm($form)
/**
* @inheritdoc
*/
public function createAnswersForm($form)
{
return true;
}
function processAnswersCreation($form)
/**
* @inheritdoc
*/
public function processAnswersCreation($form, $exercise)
{
return true;
}

@ -346,10 +346,9 @@ class FillBlanks extends Question
}
/**
* Function which creates the form to create/edit the answers of the question
* @param FormValidator $form
* @inheritdoc
*/
public function processAnswersCreation($form)
public function processAnswersCreation($form, $exercise)
{
$answer = $form->getSubmitValue('answer');
// Due the ckeditor transform the elements to their HTML value
@ -372,7 +371,7 @@ class FillBlanks extends Question
// remove spaces at the beginning and the end of text in square brackets
$answer = preg_replace_callback(
"/".$blankStartSeparatorRegexp."[^]]+".$blankEndSeparatorRegexp."/",
function($matches) use ($blankStartSeparator, $blankEndSeparator) {
function ($matches) use ($blankStartSeparator, $blankEndSeparator) {
$matchingResult = $matches[0];
$matchingResult = trim($matchingResult, $blankStartSeparator);
$matchingResult = trim($matchingResult, $blankEndSeparator);
@ -457,21 +456,18 @@ class FillBlanks extends Question
$is_multiple = $form -> getSubmitValue('multiple_answer');
$answer .= '@'.$is_multiple;
$this->save();
$this->save($exercise);
$objAnswer = new Answer($this->id);
$objAnswer->createAnswer($answer, 0, '', 0, 1);
$objAnswer->save();
}
/**
* @param null $feedback_type
* @param null $counter
* @param null $score
* @return string
* @inheritdoc
*/
public function return_header($feedback_type = null, $counter = null, $score = null)
public function return_header($exercise, $counter = null, $score = null)
{
$header = parent::return_header($feedback_type, $counter, $score);
$header = parent::return_header($exercise, $counter, $score);
$header .= '<table class="'.$this->question_table_class.'">
<tr>
<th>'.get_lang("Answer").'</th>

@ -42,22 +42,21 @@ class FreeAnswer extends Question
}
/**
* abstract function which creates the form to create/edit the answers of the question
* @param FormValidator $form
* @inheritdoc
*/
public function processAnswersCreation($form)
public function processAnswersCreation($form, $exercise)
{
$this->weighting = $form->getSubmitValue('weighting');
$this->save();
$this->save($exercise);
}
/**
* @inheritdoc
*/
public function return_header($feedback_type = null, $counter = null, $score = [])
public function return_header($exercise, $counter = null, $score = [])
{
$score['revised'] = $this->isQuestionWaitingReview($score);
$header = parent::return_header($feedback_type, $counter, $score);
$header = parent::return_header($exercise, $counter, $score);
$header .= '<table class="'.$this->question_table_class.'" >
<tr>
<th>' . get_lang("Answer").'</th>

@ -200,10 +200,9 @@ class GlobalMultipleAnswer extends Question
}
/**
* abstract function which creates the form to create / edit the answers of the question
* @param FormValidator $form
* @inheritdoc
*/
function processAnswersCreation($form)
public function processAnswersCreation($form, $exercise)
{
$objAnswer = new Answer($this->id);
$nb_answers = $form->getSubmitValue('nb_answers');
@ -254,15 +253,18 @@ class GlobalMultipleAnswer extends Question
// sets the total weighting of the question --> sert <EFBFBD> donner le score total pendant l'examen
$this->updateWeighting($questionWeighting);
$this->save();
$this->save($exercise);
}
/**
* @inheritdoc
*/
public function return_header(
$feedback_type = null,
$exercise,
$counter = null,
$score = null
) {
$header = parent::return_header($feedback_type, $counter, $score);
$header = parent::return_header($exercise, $counter, $score);
$header .= '<table class="'.$this->question_table_class.'">
<tr>
<th>' . get_lang("Choice").'</th>

@ -30,12 +30,11 @@ class HotSpot extends Question
}
/**
* @param FormValidator $form
* @param int $fck_config
*/
public function createForm(&$form, $fck_config = 0)
* @inheritdoc
*/
public function createForm(&$form, $exercise)
{
parent::createForm($form, $fck_config);
parent::createForm($form, $exercise);
if (!isset($_GET['editQuestion'])) {
$icon = Display::return_icon(
@ -100,7 +99,10 @@ class HotSpot extends Question
// nothing
}
function processAnswersCreation($form)
/**
* @inheritdoc
*/
public function processAnswersCreation($form, $exercise)
{
// nothing
}
@ -120,12 +122,15 @@ class HotSpotDelineation extends HotSpot
public function __construct()
{
parent::__construct();
$this -> type = HOT_SPOT_DELINEATION;
$this->type = HOT_SPOT_DELINEATION;
}
public function createForm(&$form, $fck_config = 0)
/**
* @inheritdoc
*/
public function createForm(&$form, $exercise)
{
parent::createForm($form, $fck_config);
parent::createForm($form);
}
public function processCreation($form, $objExercise = null)
@ -139,8 +144,11 @@ class HotSpotDelineation extends HotSpot
parent::createAnswersForm($form);
}
public function processAnswersCreation($form)
/**
* @inheritdoc
*/
public function processAnswersCreation($form, $exercise)
{
parent::processAnswersCreation($form);
parent::processAnswersCreation($form, $exercise);
}
}

@ -239,10 +239,9 @@ class Matching extends Question
}
/**
* abstract function which creates the form to create / edit the answers of the question
* @param FormValidator $form
* @inheritdoc
*/
public function processAnswersCreation($form)
public function processAnswersCreation($form, $exercise)
{
$nb_matches = $form->getSubmitValue('nb_matches');
$nb_options = $form->getSubmitValue('nb_options');
@ -274,18 +273,15 @@ class Matching extends Question
);
}
$objAnswer->save();
$this->save();
$this->save($exercise);
}
/**
* @param null $feedback_type
* @param null $counter
* @param null $score
* @return string
* @inheritdoc
*/
public function return_header($feedback_type = null, $counter = null, $score = null)
public function return_header($exercise, $counter = null, $score = null)
{
$header = parent::return_header($feedback_type, $counter, $score);
$header = parent::return_header($exercise, $counter, $score);
$header .= '<table class="'.$this->question_table_class.'">';
$header .= '<tr>
<th>'.get_lang('ElementList').'</th>

@ -182,19 +182,17 @@ class MultipleAnswer extends Question
}
/**
* abstract function which creates the form to create / edit the answers of the question
* @param the formvalidator instance
* @param the answers number to display
* @inheritdoc
*/
function processAnswersCreation($form)
public function processAnswersCreation($form, $exercise)
{
$questionWeighting = $nbrGoodAnswers = 0;
$objAnswer = new Answer($this->id);
$nb_answers = $form->getSubmitValue('nb_answers');
for ($i = 1; $i <= $nb_answers; $i++) {
$answer = trim(str_replace(['<p>', '</p>'], '', $form -> getSubmitValue('answer['.$i.']')));
$comment = trim(str_replace(['<p>', '</p>'], '', $form -> getSubmitValue('comment['.$i.']')));
$answer = trim(str_replace(['<p>', '</p>'], '', $form->getSubmitValue('answer['.$i.']')));
$comment = trim(str_replace(['<p>', '</p>'], '', $form->getSubmitValue('comment['.$i.']')));
$weighting = trim($form -> getSubmitValue('weighting['.$i.']'));
$goodAnswer = trim($form -> getSubmitValue('correct['.$i.']'));
@ -221,12 +219,15 @@ class MultipleAnswer extends Question
// sets the total weighting of the question
$this->updateWeighting($questionWeighting);
$this->save();
}
$this->save($exercise);
}
function return_header($feedback_type = null, $counter = null, $score = null)
/**
* @inheritdoc
*/
public function return_header($exercise, $counter = null, $score = null)
{
$header = parent::return_header($feedback_type, $counter, $score);
$header = parent::return_header($exercise, $counter, $score);
$header .= '<table class="'.$this->question_table_class.'">
<tr>
<th>'.get_lang("Choice").'</th>

@ -177,10 +177,9 @@ class MultipleAnswerCombination extends Question
}
/**
* abstract function which creates the form to create/edit the answers of the question
* @param FormValidator $form
* @inheritdoc
*/
public function processAnswersCreation($form)
public function processAnswersCreation($form, $exercise)
{
$questionWeighting = $nbrGoodAnswers = 0;
$objAnswer = new Answer($this->id);
@ -219,12 +218,15 @@ class MultipleAnswerCombination extends Question
// sets the total weighting of the question
$this->updateWeighting($questionWeighting);
$this->save();
$this->save($exercise);
}
function return_header($feedback_type = null, $counter = null, $score = null)
/**
* @inheritdoc
*/
public function return_header($exercise, $counter = null, $score = null)
{
$header = parent::return_header($feedback_type, $counter, $score);
$header = parent::return_header($exercise, $counter, $score);
$header .= '<table class="'.$this->question_table_class.'">
<tr>
<th>'.get_lang("Choice").'</th>

@ -235,15 +235,13 @@ class MultipleAnswerTrueFalse extends Question
}
/**
* abstract function which creates the form to create / edit the answers of the question
* @param FormValidator $form
*/
public function processAnswersCreation($form)
* @inheritdoc
*/
public function processAnswersCreation($form, $exercise)
{
$questionWeighting = $nbrGoodAnswers = 0;
$objAnswer = new Answer($this->id);
$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();
$correct = array();
@ -273,7 +271,7 @@ class MultipleAnswerTrueFalse extends Question
$new_options = Question::readQuestionOption($this->id, $course_id);
$sorted_by_position = array();
foreach ($new_options as $item) {
$sorted_by_position[$item['position']] = $item;
$sorted_by_position[$item['position']] = $item;
}
/* Saving quiz_question.extra values that has the correct scores of
@ -295,7 +293,7 @@ class MultipleAnswerTrueFalse extends Question
// 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
$questionWeighting += $extra_values[0]; //By default 0 has the correct answers
$objAnswer->createAnswer($answer, $goodAnswer, $comment, '', $i);
}
@ -303,28 +301,25 @@ class MultipleAnswerTrueFalse extends Question
$objAnswer->save();
// sets the total weighting of the question
$this->updateWeighting($questionWeighting);
$this->save();
$this->save($exercise);
}
/**
* @param int $feedback_type
* @param int $counter
* @param float $score
* @return null|string
* @inheritdoc
*/
function return_header($feedback_type = null, $counter = null, $score = null)
public function return_header($exercise, $counter = null, $score = null)
{
$header = parent::return_header($feedback_type, $counter, $score);
$header = parent::return_header($exercise, $counter, $score);
$header .= '<table class="'.$this->question_table_class.'">
<tr>
<th>'.get_lang("Choice").'</th>
<th>'. get_lang("ExpectedChoice").'</th>
<th>'. get_lang("Answer").'</th>';
if ($feedback_type != EXERCISE_FEEDBACK_TYPE_EXAM) {
$header .= '<th>'.get_lang("Comment").'</th>';
} else {
$header .= '<th>&nbsp;</th>';
}
if ($exercise->feedback_type != EXERCISE_FEEDBACK_TYPE_EXAM) {
$header .= '<th>'.get_lang("Comment").'</th>';
} else {
$header .= '<th>&nbsp;</th>';
}
$header .= '</tr>';
return $header;
}

@ -55,25 +55,21 @@ class OralExpression extends Question
}
/**
* abstract function which creates the form to create / edit the answers of the question
* @param the FormValidator $form
* @inheritdoc
*/
function processAnswersCreation($form)
public function processAnswersCreation($form, $exercise)
{
$this->weighting = $form->getSubmitValue('weighting');
$this->save();
$this->save($exercise);
}
/**
* @param null $feedback_type
* @param null $counter
* @param null $score
* @return null|string
* @inheritdoc
*/
public function return_header($feedback_type = null, $counter = null, $score = null)
public function return_header($exercise, $counter = null, $score = null)
{
$score['revised'] = $this->isQuestionWaitingReview($score);
$header = parent::return_header($feedback_type, $counter, $score);
$header = parent::return_header($exercise, $counter, $score);
$header .= '<table class="'.$this->question_table_class.'">
<tr>
<th>&nbsp;</th>

@ -1,10 +1,12 @@
<?php
/* For licensing terms, see /license.txt */
use Chamilo\CourseBundle\Entity\CQuizAnswer;
/**
* Class Question
*
* This class allows to instantiate an object of type Question
* This class allows to instantiate an object of type Question
*
* @author Olivier Brouckaert, original author
* @author Patrick Cool, LaTeX support
@ -28,9 +30,11 @@ abstract class Question
public $category;
public $isContent;
public $course;
public $feedback;
public static $typePicture = 'new_question.png';
public static $explanationLangVar = '';
public $question_table_class = 'table table-striped';
public $questionTypeWithFeedback;
public static $questionTypes = array(
UNIQUE_ANSWER => array('unique_answer.class.php', 'UniqueAnswer'),
MULTIPLE_ANSWER => array('multiple_answer.class.php', 'MultipleAnswer'),
@ -79,6 +83,12 @@ abstract class Question
$this->course = api_get_course_info();
$this->category_list = array();
$this->parent_id = 0;
$this->questionTypeWithFeedback = [
MATCHING,
MATCHING_DRAGGABLE,
DRAGGABLE,
FILL_IN_BLANKS
];
}
/**
@ -107,7 +117,6 @@ abstract class Question
public static function read($id, $course_id = null)
{
$id = intval($id);
if (!empty($course_id)) {
$course_info = api_get_course_info_by_id($course_id);
} else {
@ -123,10 +132,9 @@ abstract class Question
$TBL_QUESTIONS = Database::get_course_table(TABLE_QUIZ_QUESTION);
$TBL_EXERCISE_QUESTION = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
$sql = "SELECT question, description, ponderation, position, type, picture, level, extra
$sql = "SELECT *
FROM $TBL_QUESTIONS
WHERE c_id = $course_id AND id = $id ";
$result = Database::query($sql);
// if the question has been found
@ -143,6 +151,7 @@ abstract class Question
$objQuestion->level = (int) $object->level;
$objQuestion->extra = $object->extra;
$objQuestion->course = $course_info;
$objQuestion->feedback = isset($object->feedback) ? $object->feedback : '';
$objQuestion->category = TestCategory::getCategoryForQuestion($id);
$tblQuiz = Database::get_course_table(TABLE_QUIZ_TEST);
@ -881,7 +890,8 @@ abstract class Question
}
/**
* Sets the title
* Set title
* @param string $title
*/
public function setTitle($title)
{
@ -902,13 +912,14 @@ abstract class Question
* if an exercise ID is provided, we add that exercise ID into the exercise list
*
* @author Olivier Brouckaert
* @param integer $exerciseId - exercise ID if saving in an exercise
* @param Exercise $exercise
*/
public function save($exerciseId = 0)
public function save($exercise)
{
$TBL_EXERCISE_QUESTION = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
$TBL_QUESTIONS = Database::get_course_table(TABLE_QUIZ_QUESTION);
$em = Database::getManager();
$exerciseId = $exercise->id;
$id = $this->id;
$question = $this->question;
@ -934,6 +945,9 @@ abstract class Question
'extra' => $extra,
'level' => $level,
];
if ($exercise->questionFeedbackEnabled) {
$params['feedback'] = $this->feedback;
}
Database::update(
$TBL_QUESTIONS,
$params,
@ -952,7 +966,7 @@ abstract class Question
}
if (api_get_setting('search_enabled') == 'true') {
if ($exerciseId != 0) {
$this -> search_engine_edit($exerciseId);
$this->search_engine_edit($exerciseId);
} else {
/**
* actually there is *not* an user interface for
@ -987,6 +1001,10 @@ abstract class Question
'level' => $level
];
if ($exercise->questionFeedbackEnabled) {
$params['feedback'] = $this->feedback;
}
$this->id = Database::insert($TBL_QUESTIONS, $params);
if ($this->id) {
@ -1003,7 +1021,7 @@ abstract class Question
// If hotspot, create first answer
if ($type == HOT_SPOT || $type == HOT_SPOT_ORDER) {
$quizAnswer = new \Chamilo\CourseBundle\Entity\CQuizAnswer();
$quizAnswer = new CQuizAnswer();
$quizAnswer
->setCId($c_id)
->setQuestionId($this->id)
@ -1029,7 +1047,7 @@ abstract class Question
}
if ($type == HOT_SPOT_DELINEATION) {
$quizAnswer = new \Chamilo\CourseBundle\Entity\CQuizAnswer();
$quizAnswer = new CQuizAnswer();
$quizAnswer
->setCId($c_id)
->setQuestionId($this->id)
@ -1523,7 +1541,6 @@ abstract class Question
if (!is_null($type)) {
list($file_name, $class_name) = self::get_question_type($type);
if (!empty($file_name)) {
include_once $file_name;
if (class_exists($class_name)) {
return new $class_name();
} else {
@ -1539,8 +1556,9 @@ abstract class Question
* Creates the form to create / edit a question
* A subclass can redefine this function to add fields...
* @param FormValidator $form
* @param Exercise $exercise
*/
public function createForm(&$form)
public function createForm(&$form, $exercise)
{
echo '<style>
.media { display:none;}
@ -1563,7 +1581,14 @@ abstract class Question
// question name
if (api_get_configuration_value('save_titles_as_html')) {
$editorConfig = ['ToolbarSet' => 'Minimal'];
$form->addHtmlEditor('questionName', get_lang('Question'), false, false, $editorConfig, true);
$form->addHtmlEditor(
'questionName',
get_lang('Question'),
false,
false,
$editorConfig,
true
);
} else {
$form->addElement('text', 'questionName', get_lang('Question'));
}
@ -1589,7 +1614,13 @@ abstract class Question
$form->addButtonAdvancedSettings('advanced_params');
$form->addElement('html', '<div id="advanced_params_options" style="display:none">');
$form->addHtmlEditor('questionDescription', get_lang('QuestionDescription'), false, false, $editorConfig);
$form->addHtmlEditor(
'questionDescription',
get_lang('QuestionDescription'),
false,
false,
$editorConfig
);
// hidden values
$my_id = isset($_REQUEST['myid']) ? intval($_REQUEST['myid']) : null;
@ -1669,12 +1700,20 @@ abstract class Question
}
}
if (!is_null($exercise)) {
if ($exercise->questionFeedbackEnabled && $this->showFeedback($exercise)) {
$form->addTextarea('feedback', get_lang('FeedbackIfCorrect'));
}
}
// default values
$defaults = array();
$defaults['questionName'] = $this->question;
$defaults['questionDescription'] = $this->description;
$defaults['questionLevel'] = $this->level;
$defaults['questionCategory'] = $this->category;
$defaults['feedback'] = $this->feedback;
// Came from he question pool
if (isset($_GET['fromExercise'])) {
@ -1693,22 +1732,23 @@ abstract class Question
/**
* function which process the creation of questions
* @param FormValidator $form
* @param Exercise $objExercise
* @param Exercise $exercise
*/
public function processCreation($form, $objExercise = null)
public function processCreation($form, $exercise)
{
$this->updateTitle($form->getSubmitValue('questionName'));
$this->updateDescription($form->getSubmitValue('questionDescription'));
$this->updateLevel($form->getSubmitValue('questionLevel'));
$this->updateCategory($form->getSubmitValue('questionCategory'));
$this->setFeedback($form->getSubmitValue('feedback'));
//Save normal question if NOT media
if ($this->type != MEDIA_QUESTION) {
$this->save($objExercise->id);
$this->save($exercise);
// modify the exercise
$objExercise->addToList($this->id);
$objExercise->update_question_positions();
$exercise->addToList($this->id);
$exercise->update_question_positions();
}
}
@ -1720,9 +1760,10 @@ abstract class Question
/**
* abstract function which process the creation of answers
* @param the FormValidator $form
* @param FormValidator $form
* @param Exercise $exercise
*/
abstract public function processAnswersCreation($form);
abstract public function processAnswersCreation($form, $exercise);
/**
* Displays the menu of question types
@ -1763,8 +1804,6 @@ abstract class Question
eval('$explanation = get_lang('.$a_type[1].'::$explanationLangVar);');
echo '<li>';
echo '<div class="icon-image">';
$icon = '<a href="admin.php?'.api_get_cidreq().'&newQuestion=yes&answerType='.$i.'">'.
Display::return_icon($img, $explanation, null, ICON_SIZE_BIG).'</a>';
@ -1886,13 +1925,14 @@ abstract class Question
/**
* Shows question title an description
*
* @param string $feedback_type
* @param Exercise $exercise
* @param int $counter
* @param array $score
* @return string HTML string with the header of the question (before the answers table)
*/
public function return_header($feedback_type = null, $counter = null, $score = [])
public function return_header($exercise, $counter = null, $score = [])
{
$feedbackType = $exercise->feedback_type;
$counter_label = '';
if (!empty($counter)) {
$counter_label = intval($counter);
@ -1950,6 +1990,12 @@ abstract class Question
$header .= $message.'<br />';
}
if (isset($score['pass']) && $score['pass'] === true) {
if ($this->showFeedback($exercise)) {
$header .= $this->returnFormatFeedback();
}
}
return $header;
}
@ -2043,6 +2089,8 @@ abstract class Question
* Get course medias
* @param int course id
* @param integer $course_id
*
* @return array
*/
static function get_course_medias(
$course_id,
@ -2173,7 +2221,6 @@ abstract class Question
return $swappedAnswer;
}
/**
* @param array $score
* @return bool
@ -2187,4 +2234,31 @@ abstract class Question
return $isReview;
}
/**
* @param string $value
*/
public function setFeedback($value)
{
$this->feedback = $value;
}
/**
* @param Exercise $exercise
* @return bool
*/
public function showFeedback($exercise)
{
return
in_array($this->type, $this->questionTypeWithFeedback) &&
$exercise->feedback_type != EXERCISE_FEEDBACK_TYPE_EXAM;
}
/**
* @return string
*/
public function returnFormatFeedback()
{
return '<br /><br />'.Display::return_message($this->feedback, 'normal', false);
}
}

@ -13,7 +13,7 @@ if (isset($_GET['editQuestion'])) {
$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']);
$objQuestion = Question::getInstance($_REQUEST['answerType']);
$action = api_get_self()."?".api_get_cidreq()."&modifyQuestion=".$modifyQuestion."&newQuestion=".$newQuestion;
}
@ -37,7 +37,7 @@ if (is_object($objQuestion)) {
$form->addHeader($text.': '.$form_title_extra);
// question form elements
$objQuestion->createForm($form);
$objQuestion->createForm($form, $objExercise);
// answer form elements
$objQuestion->createAnswersForm($form);
@ -51,15 +51,14 @@ if (is_object($objQuestion)) {
if (isset($_POST['submitQuestion']) && $form->validate()) {
// Question
$objQuestion->processCreation($form, $objExercise);
// Answers
$nb_answers = isset($nb_answers) ? $nb_answers : 0;
$objQuestion->processAnswersCreation($form, $nb_answers);
$objQuestion->processAnswersCreation($form, $objExercise);
// 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 ($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 {

@ -74,7 +74,7 @@ if ($show_headers) {
$message = Session::read('attempt_remaining');
Session::erase('attempt_remaining');
ExerciseLib::display_question_list_by_attempt(
ExerciseLib::displayQuestionListByAttempt(
$objExercise,
$id,
false,

@ -316,11 +316,9 @@ class UniqueAnswer extends Question
}
/**
* Receives the unique answer question type creation form data and creates
* or updates the answers from that question
* @param FormValidator $form
* @inheritdoc
*/
public function processAnswersCreation($form)
public function processAnswersCreation($form, $exercise)
{
$questionWeighting = $nbrGoodAnswers = 0;
$correct = $form->getSubmitValue('correct');
@ -405,27 +403,23 @@ class UniqueAnswer extends Question
// sets the total weighting of the question
$this->updateWeighting($questionWeighting);
$this->save();
$this->save($exercise);
}
/**
* Helper function to print the column titles in the answers edition form
* @param null $feedback_type The type of feedback influences what columns are shown to the editor
* @param null $counter The number of answers to show, in case there should be pagination
* @param null $score The maximum score for the question
* @return string HTML string for a table header + a wrapper before it
* @inheritdoc
*/
public function return_header(
$feedback_type = null,
$exercise,
$counter = null,
$score = null
) {
$header = parent::return_header($feedback_type, $counter, $score);
$header = parent::return_header($exercise, $counter, $score);
$header .= '<table class="'.$this->question_table_class.'">
<tr>
<th>' . get_lang("Choice").'</th>
<th>' . get_lang("ExpectedChoice").'</th>
<th>' . get_lang("Answer").'</th>';
<th>'.get_lang("Choice").'</th>
<th>'.get_lang("ExpectedChoice").'</th>
<th>'.get_lang("Answer").'</th>';
$header .= '<th>'.get_lang("Comment").'</th>';
$header .= '</tr>';

@ -284,11 +284,9 @@ class UniqueAnswerNoOption extends Question
}
/**
* Function which creates the form to create / edit the answers of the question
* @param the formvalidator instance
* @param the answers number to display
*/
function processAnswersCreation($form)
* @inheritdoc
*/
public function processAnswersCreation($form, $exercise)
{
$questionWeighting = $nbrGoodAnswers = 0;
$correct = $form->getSubmitValue('correct');
@ -398,17 +396,20 @@ class UniqueAnswerNoOption extends Question
// sets the total weighting of the question
$this->updateWeighting($questionWeighting);
$this->save();
$this->save($exercise);
}
function return_header($feedback_type = null, $counter = null, $score = null)
/**
* @inheritdoc
*/
public function return_header($exercise, $counter = null, $score = null)
{
$header = parent::return_header($feedback_type, $counter, $score);
$header = parent::return_header($exercise, $counter, $score);
$header .= '<table class="'.$this->question_table_class.'">
<tr>
<th>'.get_lang("Choice").'</th>
<th>'. get_lang("ExpectedChoice").'</th>
<th>'. get_lang("Answer").'</th>';
<th>'.get_lang("ExpectedChoice").'</th>
<th>'.get_lang("Answer").'</th>';
$header .= '<th>'.get_lang("Comment").'</th>';
$header .= '</tr>';

@ -3630,7 +3630,7 @@ HOTSPOT;
* @param bool $save_user_result save users results (true) or just show the results (false)
* @param string $remainingMessage
*/
public static function display_question_list_by_attempt(
public static function displayQuestionListByAttempt(
$objExercise,
$exe_id,
$save_user_result = false,
@ -3817,7 +3817,6 @@ HOTSPOT;
// Category report
$category_was_added_for_this_test = false;
if (isset($objQuestionTmp->category) && !empty($objQuestionTmp->category)) {
if (!isset($category_list[$objQuestionTmp->category]['score'])) {
$category_list[$objQuestionTmp->category]['score'] = 0;
@ -3851,7 +3850,8 @@ HOTSPOT;
$category_list['none']['total'] += $my_total_weight;
}
if ($objExercise->selectPropagateNeg() == 0 && $my_total_score < 0
if ($objExercise->selectPropagateNeg() == 0 &&
$my_total_score < 0
) {
$my_total_score = 0;
}
@ -3866,7 +3866,7 @@ HOTSPOT;
}
if ($show_results) {
$score = array(
$score = [
'result' => self::show_score(
$my_total_score,
$my_total_weight,
@ -3877,9 +3877,9 @@ HOTSPOT;
'score' => $my_total_score,
'weight' => $my_total_weight,
'comments' => $comnt,
);
];
} else {
$score = array();
$score = [];
}
if (in_array($objQuestionTmp->type, [FREE_ANSWER, ORAL_EXPRESSION])) {
@ -3895,7 +3895,7 @@ HOTSPOT;
$question_content = '<div class="question_row_answer">';
// Shows question title an description
$question_content .= $objQuestionTmp->return_header(
null,
$objExercise,
$counter,
$score
);
@ -3940,6 +3940,7 @@ HOTSPOT;
"ExerciseWithFeedbackWithoutCorrectionComment"
)."</div>";
}
// Remove audio auto play from questions on results page - refs BT#7939
$exercise_content = preg_replace(
['/autoplay[\=\".+\"]+/', '/autostart[\=\".+\"]+/'],

@ -386,3 +386,5 @@ $_configuration['agenda_legend'] = [
// If the MySpace page takes too long to load, you might want to remove the
// processing of generic statistics for the user. In this case set the following to true.
//$_configuration['tracking_skip_generic_data'] = false;
// Show question feedback (requires DB change)
//$_configuration['allow_quiz_question_feedback'] = false;

Loading…
Cancel
Save