MDL-63186 question: include random questions in statistics calculator

Part of MDL-62610
This commit is contained in:
Ryan Wyllie
2018-09-28 11:07:21 +08:00
committed by Simey Lameze
parent 81bbf426f6
commit 29cc55079a
4 changed files with 146 additions and 23 deletions
@@ -115,4 +115,5 @@ $string['statisticsreportgraph'] = 'Statistics for question positions';
$string['statistics:view'] = 'View statistics report';
$string['statsfor'] = 'Quiz statistics (for {$a})';
$string['variant'] = 'Variant';
$string['viewdisplayedquestions'] = 'View displayed questions';
$string['whichtries'] = 'Analyze responses for';
@@ -26,6 +26,7 @@ defined('MOODLE_INTERNAL') || die();
require_once($CFG->libdir.'/tablelib.php');
use \core_question\statistics\questions\calculated_random_question_summary;
/**
* This table has one row for each question in the quiz, with sub-rows when
* random questions and variants appear.
@@ -160,7 +161,11 @@ class quiz_statistics_table extends flexible_table {
* @return string contents of this table cell.
*/
protected function col_icon($questionstat) {
return print_question_icon($questionstat->question, true);
if ($this->is_random_question_summary($questionstat)) {
return '';
} else {
return print_question_icon($questionstat->question, true);
}
}
/**
@@ -169,8 +174,12 @@ class quiz_statistics_table extends flexible_table {
* @return string contents of this table cell.
*/
protected function col_actions($questionstat) {
return quiz_question_action_icons($this->quiz, $this->cmid,
$questionstat->question, $this->baseurl, $questionstat->variant);
if ($this->is_random_question_summary($questionstat)) {
return '';
} else {
return quiz_question_action_icons($this->quiz, $this->cmid,
$questionstat->question, $this->baseurl, $questionstat->variant);
}
}
/**
@@ -227,8 +236,19 @@ class quiz_statistics_table extends flexible_table {
// Question in a slot, we are not on a page showing structural analysis of one slot,
// we don't want linking on those pages.
$number = $questionstat->question->number;
$israndomquestion = $questionstat->question->qtype == 'random';
$url = new moodle_url($baseurl, array('slot' => $questionstat->slot));
if ($questionstat->get_variants() || $questionstat->get_sub_question_ids()) {
if ($israndomquestion) {
if ($this->is_random_question_summary($questionstat)) {
// Only make the random question summary row name link to the slot structure
// analysis page with specific text to clearly indicate the link to the user.
// Random question rows will render the name without a link to improve clarity
// in the UI.
$name = html_writer::link($url,
get_string('viewdisplayedquestions', 'quiz_statistics'),
array('title' => get_string('slotstructureanalysis', 'quiz_statistics', $number)));
}
} else if ($questionstat->get_variants() || $questionstat->get_sub_question_ids()) {
// Question can be broken down into sub-questions or variants. Link will show structural analysis page.
$name = html_writer::link($url,
$name,
@@ -261,6 +281,10 @@ class quiz_statistics_table extends flexible_table {
* @return string contents of this table cell.
*/
protected function col_s($questionstat) {
if ($this->is_random_question_summary($questionstat)) {
return '';
}
if (!isset($questionstat->s)) {
return 0;
}
@@ -315,6 +339,10 @@ class quiz_statistics_table extends flexible_table {
* @return string contents of this table cell.
*/
protected function col_intended_weight($questionstat) {
if ($this->is_random_question_summary($questionstat)) {
return '';
}
return quiz_report_scale_summarks_as_percentage($questionstat->maxmark, $this->quiz);
}
@@ -388,6 +416,16 @@ class quiz_statistics_table extends flexible_table {
return $questionstat->discriminativeefficiency < 15;
}
/**
* Check if the given stats object is an instance of calculated_random_question_summary.
*
* @param \core_question\statistics\questions\calculated $questionstat Stats object
* @return bool
*/
protected function is_random_question_summary($questionstat) {
return $questionstat instanceof calculated_random_question_summary;
}
public function wrap_html_start() {
// Horrible Moodle 2.0 wide-content work-around.
if (!$this->is_downloading()) {
@@ -410,29 +410,41 @@ class all_calculated_for_qubaid_condition {
protected function all_subq_and_variant_stats_for_slot($slot, $limited) {
// Random question in this slot?
if ($this->for_slot($slot)->get_sub_question_ids()) {
if ($limited) {
$subqvariantstats = $this->all_subq_variants_for_one_slot($slot);
if ($this->too_many_subq_and_or_variant_rows($subqvariantstats)) {
// Too many variants from randomly selected questions.
return $this->find_min_median_and_max_facility_stats_objects($subqvariantstats);
}
$subqstats = $this->all_subqs_for_one_slot($slot);
if ($this->too_many_subq_and_or_variant_rows($subqstats)) {
// Too many randomly selected questions.
return $this->find_min_median_and_max_facility_stats_objects($subqstats);
}
}
$toreturn = array();
$displaynumber = 1;
foreach ($this->for_slot($slot)->get_sub_question_ids() as $subqid) {
$toreturn[] = $this->make_new_subq_stat_for($displaynumber, $slot, $subqid);
if ($variants = $this->for_subq($subqid)->get_variants()) {
foreach ($variants as $variant) {
$toreturn[] = $this->make_new_subq_stat_for($displaynumber, $slot, $subqid, $variant);
if ($limited) {
$randomquestioncalculated = $this->for_slot($slot);
// If we're showing a limited view of the statistics then add a
// random question summary stat rather than a stat for each
// subquestion.
$toreturn[] = $this->make_new_random_question_summary_stat($randomquestioncalculated);
if ($subqvariantstats = $this->all_subq_variants_for_one_slot($slot)) {
$subqvariantfacilitystats = $this->find_min_median_and_max_facility_stats_objects($subqvariantstats);
$toreturn = array_merge($toreturn, $subqvariantfacilitystats);
}
if ($subqstats = $this->all_subqs_for_one_slot($slot)) {
$subqfacilitystats = $this->find_min_median_and_max_facility_stats_objects($subqstats);
$toreturn = array_merge($toreturn, $subqfacilitystats);
}
foreach ($toreturn as $index => $calculated) {
$calculated->subqdisplayorder = $index + 1;
}
} else {
$displaynumber = 1;
foreach ($this->for_slot($slot)->get_sub_question_ids() as $subqid) {
$toreturn[] = $this->make_new_subq_stat_for($displaynumber, $slot, $subqid);
if ($variants = $this->for_subq($subqid)->get_variants()) {
foreach ($variants as $variant) {
$toreturn[] = $this->make_new_subq_stat_for($displaynumber, $slot, $subqid, $variant);
}
}
$displaynumber++;
}
$displaynumber++;
}
return $toreturn;
} else {
$variantstats = $this->all_variant_stats_for_one_slot($slot);
@@ -460,4 +472,21 @@ class all_calculated_for_qubaid_condition {
$slotstat->subqdisplayorder = $displaynumber;
return $slotstat;
}
/**
* Create a summary calculated object for a random question. This is used as a placeholder
* to indicate that a random question has sub questions to show rather than listing each
* subquestion directly.
*
* @param calculated $randomquestioncalculated The calculated instance for the random question slot.
* @return calculated_random_question_summary
*/
protected function make_new_random_question_summary_stat($randomquestioncalculated) {
$question = $randomquestioncalculated->question;
$slot = $randomquestioncalculated->slot;
$calculatedsummary = new calculated_random_question_summary($question, $slot);
$calculatedsummary->subquestions = $randomquestioncalculated->subquestions;
return $calculatedsummary;
}
}
@@ -0,0 +1,55 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Question statistics calculations class. Used in the quiz statistics report.
*
* @package core_question
* @copyright 2018 Ryan Wyllie <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_question\statistics\questions;
defined('MOODLE_INTERNAL') || die();
/**
* Class calculated_random_question_summary
*
* This class is used to indicate the statistics for a random question slot should
* be rendered with a link to a summary of the displayed questions.
*
* It's used in the limited view of the statistics calculation in lieu of adding
* the stats for each subquestion individually.
*
* @copyright 2018 Ryan Wyllie <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class calculated_random_question_summary extends calculated {
/**
* @var int only set immediately before display in the table. The order of display in the table.
*/
public $subqdisplayorder;
/**
* This is a summary stat so never breakdown by variant.
*
* @return bool
*/
public function break_down_by_variant() {
return false;
}
}