MDL-76843 quiz: fix statistics questions for missing questions

This commit is contained in:
Tim Hunt 2023-02-22 11:35:38 +00:00
parent d6f0ad4980
commit 291d241981
7 changed files with 85 additions and 30 deletions

View File

@ -940,23 +940,18 @@ function question_load_questions($questionids, $extrafields = '', $join = '') {
* @param stdClass[]|null $filtercourses The courses to filter the course tags by.
*/
function _tidy_question($question, $category, array $tagobjects = null, array $filtercourses = null): void {
// Load question-type specific fields.
if (!question_bank::is_qtype_installed($question->qtype)) {
$question->questiontext = html_writer::tag('p', get_string('warningmissingtype',
'qtype_missingtype')) . $question->questiontext;
}
// Convert numeric fields to float (Prevents these being displayed as 1.0000000.).
// Convert numeric fields to float. This prevents these being displayed as 1.0000000.
$question->defaultmark += 0;
$question->penalty += 0;
// Indicate the question is now fully initialised.
if (isset($question->_partiallyloaded)) {
unset($question->_partiallyloaded);
}
$question->categoryobject = $category;
question_bank::get_qtype($question->qtype)->get_question_options($question);
// Add any tags we have been passed.
if (!is_null($tagobjects)) {
$categorycontext = context::instance_by_id($category->contextid);
$sortedtagobjects = question_sort_tags($tagobjects, $categorycontext, $filtercourses);
@ -965,6 +960,14 @@ function _tidy_question($question, $category, array $tagobjects = null, array $f
$question->tagobjects = $sortedtagobjects->tagobjects;
$question->tags = $sortedtagobjects->tags;
}
// Load question-type specific fields.
if (question_bank::is_qtype_installed($question->qtype)) {
question_bank::get_qtype($question->qtype)->get_question_options($question);
} else {
$question->questiontext = html_writer::tag('p', get_string('warningmissingtype',
'qtype_missingtype')) . $question->questiontext;
}
}
/**

View File

@ -183,7 +183,6 @@ class qbank_helper {
$slot->category = 0;
$slot->qtype = 'missingtype';
$slot->name = get_string('missingquestion', 'quiz');
$slot->maxmark = 0;
$slot->questiontext = ' ';
$slot->questiontextformat = FORMAT_HTML;
$slot->length = 1;

View File

@ -95,7 +95,6 @@ function quiz_has_questions($quizid) {
* ->slot, ->id, ->qtype, ->length, ->number, ->maxmark, ->category (for random questions).
*/
function quiz_report_get_significant_questions($quiz) {
global $DB;
$quizobj = \quiz::create($quiz->id);
$structure = \mod_quiz\structure::create_for_quiz($quizobj);
$slots = $structure->get_slots();

View File

@ -835,33 +835,29 @@ class quiz_statistics_report extends quiz_default_report {
public function load_and_initialise_questions_for_calculations($quiz) {
// Load the questions.
$questions = quiz_report_get_significant_questions($quiz);
$questionids = [];
$randomquestions = [];
$questiondata = [];
foreach ($questions as $qs => $question) {
if ($question->qtype === 'random') {
$question->id = 0;
$question->name = get_string('random', 'quiz');
$question->questiontext = get_string('random', 'quiz');
$question->parenttype = 'random';
$randomquestions [] = $question;
unset($questions[$qs]);
continue;
$questiondata[$question->slot] = $question;
} else if ($question->qtype === 'missingtype') {
$question->id = is_numeric($question->id) ? (int) $question->id : 0;
$questiondata[$question->slot] = $question;
$question->name = get_string('deletedquestion', 'qtype_missingtype');
$question->questiontext = get_string('deletedquestiontext', 'qtype_missingtype');
} else {
$q = question_bank::load_question_data($question->id);
$q->maxmark = $question->maxmark;
$q->slot = $question->slot;
$q->number = $question->number;
$q->parenttype = null;
$questiondata[$question->slot] = $q;
}
$questionids[] = $question->id;
}
$fullquestions = question_load_questions($questionids);
foreach ($questions as $qno => $question) {
$q = $fullquestions[$question->id];
$q->maxmark = $question->maxmark;
$q->slot = $question->slot;
$q->number = $question->number;
$q->parenttype = null;
$questiondata[$question->slot] = $q;
}
foreach ($randomquestions as $randomquestion) {
$questiondata[$randomquestion->slot] = $randomquestion;
}
ksort($questiondata);
return $questiondata;
}

View File

@ -201,6 +201,8 @@ class quiz_statistics_table extends flexible_table {
protected function col_actions($questionstat) {
if ($this->is_calculated_question_summary($questionstat)) {
return '';
} else if ($questionstat->question->qtype === 'missingtype') {
return '';
} else {
$random = null;
if ($questionstat->question->qtype === 'random') {

View File

@ -0,0 +1,48 @@
@mod @mod_quiz @quiz @quiz_statistics
Feature: Robustness of the statistics calculations with missing qusetions
In order to be able to install and uninstall plugins
As a teacher
I need the statistics to work even if a question type has been uninstalled
Scenario: Statistics can be calculated even after a question type has been uninstalled
Given the following "users" exist:
| username |
| teacher |
| student |
And the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
And the following "course enrolments" exist:
| user | course | role |
| teacher | C1 | editingteacher |
| student | C1 | student |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name |
| Test questions | truefalse | Test question 1 |
| Test questions | truefalse | Test question 2 |
And the following "activities" exist:
| activity | name | course | idnumber |
| quiz | Quiz 1 | C1 | quiz1 |
And quiz "Quiz 1" contains the following questions:
| question | page |
| Test question 1 | 1 |
| Test question 2 | 1 |
And user "student" has attempted "Quiz 1" with responses:
| slot | response |
| 1 | True |
| 2 | True |
And question "Test question 1" is changed to simulate being of an uninstalled type
And question "Test question 2" no longer exists in the database
When I am on the "Quiz 1" "mod_quiz > Statistics report" page logged in as teacher
Then I should see "Quiz structure analysis"
And "1" row "Question name" column of "questionstatistics" table should contain "Missing question"
And "1" row "Attempts" column of "questionstatistics" table should contain "1"
And "1" row "Intended weight" column of "questionstatistics" table should contain "50.00%"
And "2" row "Question name" column of "questionstatistics" table should contain "Missing question"
And "2" row "Attempts" column of "questionstatistics" table should contain "1"
And "2" row "Intended weight" column of "questionstatistics" table should contain "50.00%"

View File

@ -26,6 +26,8 @@
namespace core_question\statistics\questions;
use question_bank;
/**
* A collection of all the question statistics calculated for an activity instance.
*
@ -214,7 +216,13 @@ class all_calculated_for_qubaid_condition {
} else {
$this->subquestionstats[$fromdb->questionid] = new calculated_for_subquestion();
$this->subquestionstats[$fromdb->questionid]->populate_from_record($fromdb);
$this->subquestionstats[$fromdb->questionid]->question = $this->subquestions[$fromdb->questionid];
if (isset($this->subquestions[$fromdb->questionid])) {
$this->subquestionstats[$fromdb->questionid]->question =
$this->subquestions[$fromdb->questionid];
} else {
$this->subquestionstats[$fromdb->questionid]->question =
question_bank::get_qtype('missingtype', false)->make_deleted_instance($fromdb->questionid, 1);
}
}
}
}