Skip to content

Commit

Permalink
MDL-63456 qtype_multichoice: Return a default options object if missing
Browse files Browse the repository at this point in the history
  • Loading branch information
ericmerrill committed Oct 8, 2018
1 parent 2d5d5d7 commit f55f891
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 2 deletions.
44 changes: 42 additions & 2 deletions question/type/multichoice/questiontype.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,51 @@
class qtype_multichoice extends question_type {
public function get_question_options($question) {
global $DB, $OUTPUT;
$question->options = $DB->get_record('qtype_multichoice_options',
array('questionid' => $question->id), '*', MUST_EXIST);

$question->options = $DB->get_record('qtype_multichoice_options', ['questionid' => $question->id]);

if ($question->options === false) {
// If this has happened, then we have a problem.
// For the user to be able to edit or delete this question, we need options.
debugging("Question ID {$question->id} was missing an options record. Using default.", DEBUG_DEVELOPER);

$question->options = $this->create_default_options($question);
}

parent::get_question_options($question);
}

/**
* Create a default options object for the provided question.
*
* @param object $question The queston we are working with.
* @return object The options object.
*/
protected function create_default_options($question) {
// Create a default question options record.
$options = new stdClass();
$options->questionid = $question->id;

// Get the default strings and just set the format.
$options->correctfeedback = get_string('correctfeedbackdefault', 'question');
$options->correctfeedbackformat = FORMAT_HTML;
$options->partiallycorrectfeedback = get_string('partiallycorrectfeedbackdefault', 'question');;
$options->partiallycorrectfeedbackformat = FORMAT_HTML;
$options->incorrectfeedback = get_string('incorrectfeedbackdefault', 'question');
$options->incorrectfeedbackformat = FORMAT_HTML;

$config = get_config('qtype_multichoice');
$options->single = $config->answerhowmany;
if (isset($question->layout)) {
$options->layout = $question->layout;
}
$options->answernumbering = $config->answernumbering;
$options->shuffleanswers = $config->shuffleanswers;
$options->shownumcorrect = 1;

return $options;
}

public function save_question_options($question) {
global $DB;
$context = $question->context;
Expand Down
73 changes: 73 additions & 0 deletions question/type/multichoice/tests/questiontype_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -163,4 +163,77 @@ public function test_question_saving_two_of_four($which) {
}
}
}

/**
* Test to make sure that loading of question options works, including in an error case.
*/
public function test_get_question_options() {
global $DB;

$this->resetAfterTest(true);
$this->setAdminUser();

// Create a complete, in DB question to use.
$questiondata = test_question_maker::get_question_data('multichoice', 'two_of_four');
$formdata = test_question_maker::get_question_form_data('multichoice', 'two_of_four');

$generator = $this->getDataGenerator()->get_plugin_generator('core_question');
$cat = $generator->create_question_category(array());

$formdata->category = "{$cat->id},{$cat->contextid}";
qtype_multichoice_edit_form::mock_submit((array)$formdata);

$form = qtype_multichoice_test_helper::get_question_editing_form($cat, $questiondata);

$this->assertTrue($form->is_validated());

$fromform = $form->get_data();

$returnedfromsave = $this->qtype->save_question($questiondata, $fromform);

// Now get just the raw DB record.
$question = $DB->get_record('question', ['id' => $returnedfromsave->id], '*', MUST_EXIST);

// Load it.
$this->qtype->get_question_options($question);
$this->assertDebuggingNotCalled();
$this->assertInstanceOf(stdClass::class, $question->options);

$options = $question->options;
$this->assertEquals($question->id, $options->questionid);
$this->assertEquals(0, $options->single);

$this->assertCount(4, $options->answers);

// Now we are going to delete the options record.
$DB->delete_records('qtype_multichoice_options', ['questionid' => $question->id]);

// Now see what happens.
$question = $DB->get_record('question', ['id' => $returnedfromsave->id], '*', MUST_EXIST);
$this->qtype->get_question_options($question);

$this->assertDebuggingCalled('Question ID '.$question->id.' was missing an options record. Using default.');
$this->assertInstanceOf(stdClass::class, $question->options);
$options = $question->options;
$this->assertEquals($question->id, $options->questionid);
$this->assertCount(4, $options->answers);

$this->assertEquals(get_string('correctfeedbackdefault', 'question'), $options->correctfeedback);
$this->assertEquals(FORMAT_HTML, $options->correctfeedbackformat);

// We no longer know how many answers, so it just has to guess with the default value.
$this->assertEquals(get_config('qtype_multichoice', 'answerhowmany'), $options->single);

// And finally we try again with no answer either.
$DB->delete_records('question_answers', ['question' => $question->id]);

$question = $DB->get_record('question', ['id' => $returnedfromsave->id], '*', MUST_EXIST);
$this->qtype->get_question_options($question);

$this->assertDebuggingCalled('Question ID '.$question->id.' was missing an options record. Using default.');
$this->assertInstanceOf(stdClass::class, $question->options);
$options = $question->options;
$this->assertEquals($question->id, $options->questionid);
$this->assertCount(0, $options->answers);
}
}

0 comments on commit f55f891

Please sign in to comment.