2 // This file is part of Moodle - http://moodle.org/
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
18 * Quiz statistics report class.
20 * @package quiz_statistics
21 * @copyright 2008 Jamie Pratt
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 defined('MOODLE_INTERNAL') || die();
27 require_once($CFG->dirroot . '/mod/quiz/report/statistics/statistics_form.php');
28 require_once($CFG->dirroot . '/mod/quiz/report/statistics/statistics_table.php');
29 require_once($CFG->dirroot . '/mod/quiz/report/statistics/statistics_question_table.php');
30 require_once($CFG->dirroot . '/mod/quiz/report/statistics/statisticslib.php');
32 * The quiz statistics report provides summary information about each question in
33 * a quiz, compared to the whole quiz. It also provides a drill-down to more
34 * detailed information about each question.
36 * @copyright 2008 Jamie Pratt
37 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
39 class quiz_statistics_report extends quiz_default_report {
46 /** @var quiz_statistics_table instance of table class used for main questions stats table. */
49 /** @var \core\progress\base|null $progress Handles progress reporting or not. */
50 protected $progress = null;
55 public function display($quiz, $cm, $course) {
58 raise_memory_limit(MEMORY_HUGE);
60 $this->context = context_module::instance($cm->id);
62 if (!quiz_questions_in_quiz($quiz->questions)) {
63 $this->print_header_and_tabs($cm, $course, $quiz, 'statistics');
64 echo quiz_no_questions_message($quiz, $cm, $this->context);
68 // Work out the display options.
69 $download = optional_param('download', '', PARAM_ALPHA);
70 $everything = optional_param('everything', 0, PARAM_BOOL);
71 $recalculate = optional_param('recalculate', 0, PARAM_BOOL);
72 // A qid paramter indicates we should display the detailed analysis of a sub question.
73 $qid = optional_param('qid', 0, PARAM_INT);
74 $slot = optional_param('slot', 0, PARAM_INT);
75 $whichattempts = optional_param('whichattempts', $quiz->grademethod, PARAM_INT);
77 $pageoptions = array();
78 $pageoptions['id'] = $cm->id;
79 $pageoptions['mode'] = 'statistics';
81 $reporturl = new moodle_url('/mod/quiz/report.php', $pageoptions);
83 $mform = new quiz_statistics_settings_form($reporturl);
85 $mform->set_data(array('whichattempts' => $whichattempts));
87 if ($fromform = $mform->get_data()) {
88 $whichattempts = $fromform->whichattempts;
91 if ($whichattempts != $quiz->grademethod) {
92 $reporturl->param('whichattempts', $whichattempts);
95 // Find out current groups mode.
96 $currentgroup = $this->get_current_group($cm, $course, $this->context);
97 $nostudentsingroup = false; // True if a group is selected and there is no one in it.
98 if (empty($currentgroup)) {
100 $groupstudents = array();
102 } else if ($currentgroup == self::NO_GROUPS_ALLOWED) {
103 $groupstudents = array();
104 $nostudentsingroup = true;
107 // All users who can attempt quizzes and who are in the currently selected group.
108 $groupstudents = get_users_by_capability($this->context,
109 array('mod/quiz:reviewmyattempts', 'mod/quiz:attempt'),
110 '', '', '', '', $currentgroup, '', false);
111 if (!$groupstudents) {
112 $nostudentsingroup = true;
116 $qubaids = quiz_statistics_qubaids_condition($quiz->id, $groupstudents, $whichattempts);
118 // If recalculate was requested, handle that.
119 if ($recalculate && confirm_sesskey()) {
120 $this->clear_cached_data($qubaids);
121 redirect($reporturl);
124 // Set up the main table.
125 $this->table = new quiz_statistics_table();
127 $report = get_string('completestatsfilename', 'quiz_statistics');
129 $report = get_string('questionstatsfilename', 'quiz_statistics');
131 $courseshortname = format_string($course->shortname, true,
132 array('context' => context_course::instance($course->id)));
133 $filename = quiz_report_download_filename($report, $courseshortname, $quiz->name);
134 $this->table->is_downloading($download, $filename,
135 get_string('quizstructureanalysis', 'quiz_statistics'));
136 $questions = $this->load_and_initialise_questions_for_calculations($quiz);
138 // Print the page header stuff (if not downloading.
139 if (!$this->table->is_downloading()) {
140 $this->print_header_and_tabs($cm, $course, $quiz, 'statistics');
143 if (!$nostudentsingroup) {
144 // Get the data to be displayed.
145 $progress = $this->get_progress_trace_instance();
146 list($quizstats, $questionstats) =
147 $this->get_all_stats_and_analysis($quiz, $whichattempts, $groupstudents, $questions, $progress);
149 // Or create empty stats containers.
150 $quizstats = new \quiz_statistics\calculated($whichattempts);
151 $questionstats = new \core_question\statistics\questions\all_calculated_for_qubaid_condition();
154 // Set up the table, if there is data.
155 if ($quizstats->s()) {
156 $this->table->statistics_setup($quiz, $cm->id, $reporturl, $quizstats->s());
159 // Print the rest of the page header stuff (if not downloading.
160 if (!$this->table->is_downloading()) {
162 if (groups_get_activity_groupmode($cm)) {
163 groups_print_activity_menu($cm, $reporturl->out());
164 if ($currentgroup && !$groupstudents) {
165 $OUTPUT->notification(get_string('nostudentsingroup', 'quiz_statistics'));
169 if (!$this->table->is_downloading() && $quizstats->s() == 0) {
170 echo $OUTPUT->notification(get_string('noattempts', 'quiz'));
173 foreach($questionstats->any_error_messages() as $errormessage) {
174 echo $OUTPUT->notification($errormessage);
177 // Print display options form.
181 if ($everything) { // Implies is downloading.
182 // Overall report, then the analysis of each question.
183 $quizinfo = $quizstats->get_formatted_quiz_info_data($course, $cm, $quiz);
184 $this->download_quiz_info_table($quizinfo);
186 if ($quizstats->s()) {
187 $this->output_quiz_structure_analysis_table($questionstats);
189 if ($this->table->is_downloading() == 'xhtml' && $quizstats->s() != 0) {
190 $this->output_statistics_graph($quiz->id, $currentgroup, $whichattempts);
193 foreach ($questions as $slot => $question) {
194 if (question_bank::get_qtype(
195 $question->qtype, false)->can_analyse_responses()) {
196 $this->output_individual_question_response_analysis(
197 $question, $questionstats->for_slot($slot)->s, $reporturl, $qubaids);
199 } else if ($subqids = $questionstats->for_slot($slot)->get_sub_question_ids()) {
200 foreach ($subqids as $subqid) {
201 $this->output_individual_question_response_analysis($questionstats->for_subq($subqid)->question,
202 $questionstats->for_subq($subqid)->s,
210 $this->table->export_class_instance()->finish_document();
213 // Report on an individual question indexed by position.
214 if (!isset($questions[$slot])) {
215 print_error('questiondoesnotexist', 'question');
218 $this->output_individual_question_data($quiz, $questionstats->for_slot($slot));
219 $this->output_individual_question_response_analysis($questions[$slot],
220 $questionstats->for_slot($slot)->s,
224 // Back to overview link.
225 echo $OUTPUT->box('<a href="' . $reporturl->out() . '">' .
226 get_string('backtoquizreport', 'quiz_statistics') . '</a>',
227 'backtomainstats boxaligncenter generalbox boxwidthnormal mdl-align');
230 // Report on an individual sub-question indexed questionid.
231 if (is_null($questionstats->for_subq($qid))) {
232 print_error('questiondoesnotexist', 'question');
235 $this->output_individual_question_data($quiz, $questionstats->for_subq($qid));
236 $this->output_individual_question_response_analysis($questionstats->for_subq($qid)->question,
237 $questionstats->for_subq($qid)->s,
241 // Back to overview link.
242 echo $OUTPUT->box('<a href="' . $reporturl->out() . '">' .
243 get_string('backtoquizreport', 'quiz_statistics') . '</a>',
244 'boxaligncenter generalbox boxwidthnormal mdl-align');
246 } else if ($this->table->is_downloading()) {
247 // Downloading overview report.
248 $quizinfo = $quizstats->get_formatted_quiz_info_data($course, $cm, $quiz);
249 $this->download_quiz_info_table($quizinfo);
250 if ($quizstats->s()) {
251 $this->output_quiz_structure_analysis_table($questionstats);
253 $this->table->finish_output();
256 // On-screen display of overview report.
257 echo $OUTPUT->heading(get_string('quizinformation', 'quiz_statistics'), 3);
258 echo $this->output_caching_info($quizstats, $quiz->id, $groupstudents, $whichattempts, $reporturl);
259 echo $this->everything_download_options();
260 $quizinfo = $quizstats->get_formatted_quiz_info_data($course, $cm, $quiz);
261 echo $this->output_quiz_info_table($quizinfo);
262 if ($quizstats->s()) {
263 echo $OUTPUT->heading(get_string('quizstructureanalysis', 'quiz_statistics'), 3);
264 $this->output_quiz_structure_analysis_table($questionstats);
265 $this->output_statistics_graph($quiz->id, $currentgroup, $whichattempts);
273 * Display the statistical and introductory information about a question.
274 * Only called when not downloading.
275 * @param object $quiz the quiz settings.
276 * @param \core_question\statistics\questions\calculated $questionstat the question to report on.
278 protected function output_individual_question_data($quiz, $questionstat) {
281 // On-screen display. Show a summary of the question's place in the quiz,
282 // and the question statistics.
283 $datumfromtable = $this->table->format_row($questionstat);
285 // Set up the question info table.
286 $questioninfotable = new html_table();
287 $questioninfotable->align = array('center', 'center');
288 $questioninfotable->width = '60%';
289 $questioninfotable->attributes['class'] = 'generaltable titlesleft';
291 $questioninfotable->data = array();
292 $questioninfotable->data[] = array(get_string('modulename', 'quiz'), $quiz->name);
293 $questioninfotable->data[] = array(get_string('questionname', 'quiz_statistics'),
294 $questionstat->question->name.' '.$datumfromtable['actions']);
295 $questioninfotable->data[] = array(get_string('questiontype', 'quiz_statistics'),
296 $datumfromtable['icon'] . ' ' .
297 question_bank::get_qtype($questionstat->question->qtype, false)->menu_name() . ' ' .
298 $datumfromtable['icon']);
299 $questioninfotable->data[] = array(get_string('positions', 'quiz_statistics'),
300 $questionstat->positions);
302 // Set up the question statistics table.
303 $questionstatstable = new html_table();
304 $questionstatstable->align = array('center', 'center');
305 $questionstatstable->width = '60%';
306 $questionstatstable->attributes['class'] = 'generaltable titlesleft';
308 unset($datumfromtable['number']);
309 unset($datumfromtable['icon']);
310 $actions = $datumfromtable['actions'];
311 unset($datumfromtable['actions']);
312 unset($datumfromtable['name']);
314 's' => get_string('attempts', 'quiz_statistics'),
315 'facility' => get_string('facility', 'quiz_statistics'),
316 'sd' => get_string('standarddeviationq', 'quiz_statistics'),
317 'random_guess_score' => get_string('random_guess_score', 'quiz_statistics'),
318 'intended_weight' => get_string('intended_weight', 'quiz_statistics'),
319 'effective_weight' => get_string('effective_weight', 'quiz_statistics'),
320 'discrimination_index' => get_string('discrimination_index', 'quiz_statistics'),
321 'discriminative_efficiency' =>
322 get_string('discriminative_efficiency', 'quiz_statistics')
324 foreach ($datumfromtable as $item => $value) {
325 $questionstatstable->data[] = array($labels[$item], $value);
328 // Display the various bits.
329 echo $OUTPUT->heading(get_string('questioninformation', 'quiz_statistics'), 3);
330 echo html_writer::table($questioninfotable);
331 echo $this->render_question_text($questionstat->question);
332 echo $OUTPUT->heading(get_string('questionstatistics', 'quiz_statistics'), 3);
333 echo html_writer::table($questionstatstable);
337 * @param object $question question data.
338 * @return string HTML of question text, ready for display.
340 protected function render_question_text($question) {
343 $text = question_rewrite_question_preview_urls($question->questiontext, $question->id,
344 $question->contextid, 'question', 'questiontext', $question->id,
345 $this->context->id, 'quiz_statistics');
347 return $OUTPUT->box(format_text($text, $question->questiontextformat,
348 array('noclean' => true, 'para' => false, 'overflowdiv' => true)),
349 'questiontext boxaligncenter generalbox boxwidthnormal mdl-align');
353 * Display the response analysis for a question.
354 * @param object $question the question to report on.
356 * @param moodle_url $reporturl the URL to redisplay this report.
357 * @param qubaid_condition $qubaids
359 protected function output_individual_question_response_analysis($question, $s, $reporturl, $qubaids) {
362 if (!question_bank::get_qtype($question->qtype, false)->can_analyse_responses()) {
366 $qtable = new quiz_statistics_question_table($question->id);
367 $exportclass = $this->table->export_class_instance();
368 $qtable->export_class_instance($exportclass);
369 if (!$this->table->is_downloading()) {
370 // Output an appropriate title.
371 echo $OUTPUT->heading(get_string('analysisofresponses', 'quiz_statistics'), 3);
374 // Work out an appropriate title.
375 $questiontabletitle = '"' . $question->name . '"';
376 if (!empty($question->number)) {
377 $questiontabletitle = '(' . $question->number . ') ' . $questiontabletitle;
379 if ($this->table->is_downloading() == 'xhtml') {
380 $questiontabletitle = get_string('analysisofresponsesfor', 'quiz_statistics', $questiontabletitle);
384 $exportclass->start_table($questiontabletitle);
386 if ($this->table->is_downloading() == 'xhtml') {
387 echo $this->render_question_text($question);
391 $responesanalyser = new \core_question\statistics\responses\analyser($question);
392 $responseanalysis = $responesanalyser->load_cached($qubaids);
394 $qtable->question_setup($reporturl, $question, $s, $responseanalysis);
395 if ($this->table->is_downloading()) {
396 $exportclass->output_headers($qtable->headers);
398 foreach ($responseanalysis->get_subpart_ids() as $partid) {
399 $subpart = $responseanalysis->get_subpart($partid);
400 foreach ($subpart->get_response_class_ids() as $responseclassid) {
401 $responseclass = $subpart->get_response_class($responseclassid);
402 $tabledata = $responseclass->data_for_question_response_table($subpart->has_multiple_response_classes(), $partid);
403 foreach ($tabledata as $row) {
404 $qtable->add_data_keyed($qtable->format_row($row));
409 $qtable->finish_output(!$this->table->is_downloading());
413 * Output the table that lists all the questions in the quiz with their statistics.
414 * @param \core_question\statistics\questions\all_calculated_for_qubaid_condition $questionstats the stats for all questions in
415 * the quiz including subqs and
418 protected function output_quiz_structure_analysis_table($questionstats) {
420 foreach ($questionstats->get_all_slots() as $slot) {
421 // Output the data for these question statistics.
422 $tooutput[] = $questionstats->for_slot($slot);
424 $limitvariants = !$this->table->is_downloading();
425 $tooutput = array_merge($tooutput, $questionstats->all_subq_and_variant_stats_for_slot($slot, $limitvariants));
427 $this->table->format_and_add_array_of_rows($tooutput);
431 * Output the table of overall quiz statistics.
432 * @param array $quizinfo as returned by {@link get_formatted_quiz_info_data()}.
433 * @return string the HTML.
435 protected function output_quiz_info_table($quizinfo) {
437 $quizinfotable = new html_table();
438 $quizinfotable->align = array('center', 'center');
439 $quizinfotable->width = '60%';
440 $quizinfotable->attributes['class'] = 'generaltable titlesleft';
441 $quizinfotable->data = array();
443 foreach ($quizinfo as $heading => $value) {
444 $quizinfotable->data[] = array($heading, $value);
447 return html_writer::table($quizinfotable);
451 * Download the table of overall quiz statistics.
452 * @param array $quizinfo as returned by {@link get_formatted_quiz_info_data()}.
454 protected function download_quiz_info_table($quizinfo) {
457 // XHTML download is a special case.
458 if ($this->table->is_downloading() == 'xhtml') {
459 echo $OUTPUT->heading(get_string('quizinformation', 'quiz_statistics'), 3);
460 echo $this->output_quiz_info_table($quizinfo);
464 // Reformat the data ready for output.
467 foreach ($quizinfo as $heading => $value) {
468 $headers[] = $heading;
473 $exportclass = $this->table->export_class_instance();
474 $exportclass->start_table(get_string('quizinformation', 'quiz_statistics'));
475 $exportclass->output_headers($headers);
476 $exportclass->add_data($row);
477 $exportclass->finish_table();
481 * Output the HTML needed to show the statistics graph.
483 * @param $currentgroup
484 * @param $whichattempts
486 protected function output_statistics_graph($quizid, $currentgroup, $whichattempts) {
489 $output = $PAGE->get_renderer('mod_quiz');
490 $imageurl = new moodle_url('/mod/quiz/report/statistics/statistics_graph.php',
491 compact('quizid', 'currentgroup', 'whichattempts'));
492 $graphname = get_string('statisticsreportgraph', 'quiz_statistics');
493 echo $output->graph($imageurl, $graphname);
497 * Get the quiz and question statistics, either by loading the cached results,
498 * or by recomputing them.
500 * @param object $quiz the quiz settings.
501 * @param string $whichattempts which attempts to use, represented internally as one of the constants as used in
502 * $quiz->grademethod ie.
503 * QUIZ_GRADEAVERAGE, QUIZ_GRADEHIGHEST, QUIZ_ATTEMPTLAST or QUIZ_ATTEMPTFIRST
504 * we calculate stats based on which attempts would affect the grade for each student.
505 * @param array $groupstudents students in this group.
506 * @param array $questions full question data.
507 * @param \core\progress\base|null $progress
508 * @return array with 2 elements: - $quizstats The statistics for overall attempt scores.
509 * - $questionstats \core_question\statistics\questions\all_calculated_for_qubaid_condition
511 public function get_all_stats_and_analysis($quiz, $whichattempts, $groupstudents, $questions, $progress = null) {
513 if ($progress === null) {
514 $progress = new \core\progress\null();
517 $qubaids = quiz_statistics_qubaids_condition($quiz->id, $groupstudents, $whichattempts);
519 $qcalc = new \core_question\statistics\questions\calculator($questions, $progress);
521 $quizcalc = new \quiz_statistics\calculator($progress);
523 if ($quizcalc->get_last_calculated_time($qubaids) === false) {
525 $progress->start_progress('', 3);
528 $questionstats = $qcalc->calculate($qubaids);
529 $progress->progress(1);
531 $quizstats = $quizcalc->calculate($quiz->id, $whichattempts, $groupstudents, count($questions),
532 $qcalc->get_sum_of_mark_variance());
533 $progress->progress(2);
534 if ($quizstats->s()) {
535 $subquestions = $questionstats->get_sub_questions();
536 $this->analyse_responses_for_all_questions_and_subquestions($qubaids, $questions, $subquestions, $progress);
538 $progress->progress(3);
539 $progress->end_progress();
541 $quizstats = $quizcalc->get_cached($qubaids);
542 $questionstats = $qcalc->get_cached($qubaids);
545 return array($quizstats, $questionstats);
549 * Appropriate instance depending if we want html output for the user or not.
551 * @return \core\progress\base child of \core\progress\base to handle the display (or not) of task progress.
553 protected function get_progress_trace_instance() {
554 if ($this->progress === null) {
555 if (!$this->table->is_downloading()) {
556 $this->progress = new \core\progress\display_if_slow(get_string('calculatingallstats', 'quiz_statistics'));
557 $this->progress->set_display_names();
559 $this->progress = new \core\progress\null();
562 return $this->progress;
565 protected function analyse_responses_for_all_questions_and_subquestions($qubaids, $questions, $subquestions,
568 if ($progress === null) {
569 $progress = new \core\progress\null();
572 // Starting response analysis tasks.
573 $progress->start_progress('', count($questions) + count($subquestions));
575 // Starting response analysis of main questions.
576 $progress->start_progress('', count($questions), count($questions));
580 foreach ($questions as $question) {
581 $progress->progress($donecount);
583 if (!question_bank::get_qtype($question->qtype, false)->can_analyse_responses()) {
586 $done[$question->id] = 1;
588 $responesstats = new \core_question\statistics\responses\analyser($question);
589 $responesstats->calculate($qubaids);
591 $progress->end_progress();
593 // Starting response analysis of sub-questions.
594 $countsubquestions = count($subquestions);
595 $progress->start_progress('', $countsubquestions, $countsubquestions);
597 foreach ($subquestions as $subquestion) {
598 $progress->progress($donecount);
600 if (!question_bank::get_qtype($subquestion->qtype, false)->can_analyse_responses() ||
601 isset($done[$subquestion->id])) {
604 $done[$subquestion->id] = 1;
606 $responesstats = new \core_question\statistics\responses\analyser($subquestion);
607 $responesstats->calculate($qubaids);
609 // Finished sub-question tasks.
610 $progress->end_progress();
612 // Finished all response analysis tasks.
613 $progress->end_progress();
617 * @return string HTML snipped for the Download full report as UI.
619 protected function everything_download_options() {
620 $downloadoptions = $this->table->get_download_menu();
622 $downloadelements = new stdClass();
623 $downloadelements->formatsmenu = html_writer::select($downloadoptions, 'download',
624 $this->table->defaultdownloadformat, false);
625 $downloadelements->downloadbutton = '<input type="submit" value="' .
626 get_string('download') . '"/>';
628 $output = '<form action="'. $this->table->baseurl .'" method="post">';
629 $output .= '<div class="mdl-align">';
630 $output .= '<input type="hidden" name="everything" value="1"/>';
631 $output .= html_writer::tag('label', get_string('downloadeverything', 'quiz_statistics', $downloadelements));
632 $output .= '</div></form>';
638 * Generate the snipped of HTML that says when the stats were last caculated,
639 * with a recalcuate now button.
640 * @param object $quizstats the overall quiz statistics.
641 * @param int $quizid the quiz id.
642 * @param array $groupstudents ids of students in the group or empty array if groups not used.
643 * @param string $whichattempts which attempts to use, represented internally as one of the constants as used in
644 * $quiz->grademethod ie.
645 * QUIZ_GRADEAVERAGE, QUIZ_GRADEHIGHEST, QUIZ_ATTEMPTLAST or QUIZ_ATTEMPTFIRST
646 * we calculate stats based on which attempts would affect the grade for each student.
647 * @param moodle_url $reporturl url for this report
648 * @return string a HTML snipped saying when the stats were last computed,
649 * or blank if that is not appropriate.
651 protected function output_caching_info($quizstats, $quizid, $groupstudents, $whichattempts, $reporturl) {
654 if (empty($quizstats->timemodified)) {
658 // Find the number of attempts since the cached statistics were computed.
659 list($fromqa, $whereqa, $qaparams) = quiz_statistics_attempts_sql($quizid, $groupstudents, $whichattempts, true);
660 $count = $DB->count_records_sql("
664 AND quiza.timefinish > {$quizstats->timemodified}", $qaparams);
670 // Generate the output.
672 $a->lastcalculated = format_time(time() - $quizstats->timemodified);
675 $recalcualteurl = new moodle_url($reporturl,
676 array('recalculate' => 1, 'sesskey' => sesskey()));
678 $output .= $OUTPUT->box_start(
679 'boxaligncenter generalbox boxwidthnormal mdl-align', 'cachingnotice');
680 $output .= get_string('lastcalculated', 'quiz_statistics', $a);
681 $output .= $OUTPUT->single_button($recalcualteurl,
682 get_string('recalculatenow', 'quiz_statistics'));
683 $output .= $OUTPUT->box_end(true);
689 * Clear the cached data for a particular report configuration. This will
690 * trigger a re-computation the next time the report is displayed.
691 * @param $qubaids qubaid_condition
693 protected function clear_cached_data($qubaids) {
695 $DB->delete_records('quiz_statistics', array('hashcode' => $qubaids->get_hash_code()));
696 $DB->delete_records('question_statistics', array('hashcode' => $qubaids->get_hash_code()));
697 $DB->delete_records('question_response_analysis', array('hashcode' => $qubaids->get_hash_code()));
701 * @param object $quiz the quiz.
702 * @return array of questions for this quiz.
704 public function load_and_initialise_questions_for_calculations($quiz) {
705 // Load the questions.
706 $questions = quiz_report_get_significant_questions($quiz);
707 $questionids = array();
708 foreach ($questions as $question) {
709 $questionids[] = $question->id;
711 $fullquestions = question_load_questions($questionids);
712 foreach ($questions as $qno => $question) {
713 $q = $fullquestions[$question->id];
714 $q->maxmark = $question->maxmark;
716 $q->number = $question->number;
717 $questions[$qno] = $q;