mirror of
https://github.com/moodle/moodle.git
synced 2025-01-19 06:18:28 +01:00
MDL-63390 quiz_statistics, question: Handling variants as well
Variants should also be treated like random questions in the sense that a summary row should be displayed for them as well. This commit deals with handling variants. Also the name of the calculated_random_question_summary class has changed to calculated_question_summary to be more generic as the summary row is not specific to random questions only. Also removed the protected function too_many_subq_and_or_variant_rows and the const SUBQ_AND_VARIANT_ROW_LIMIT as they were not being used anymore. Part of MDL-62610
This commit is contained in:
parent
f4bc55871c
commit
84140b9137
@ -117,5 +117,4 @@ $string['statistics:view'] = 'View statistics report';
|
||||
$string['statsfor'] = 'Quiz statistics (for {$a})';
|
||||
$string['variant'] = 'Variant';
|
||||
$string['viewanalysis'] = 'View analysis of these questions';
|
||||
$string['viewanalysishint'] = 'View analysis of the random question(s) above';
|
||||
$string['whichtries'] = 'Analyze responses for';
|
||||
|
@ -26,7 +26,8 @@ defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir.'/tablelib.php');
|
||||
|
||||
use \core_question\statistics\questions\calculated_random_question_summary;
|
||||
use \core_question\statistics\questions\calculated_question_summary;
|
||||
|
||||
/**
|
||||
* This table has one row for each question in the quiz, with sub-rows when
|
||||
* random questions and variants appear.
|
||||
@ -139,7 +140,7 @@ class quiz_statistics_table extends flexible_table {
|
||||
* @return string contents of this table cell.
|
||||
*/
|
||||
protected function col_number($questionstat) {
|
||||
if ($this->is_random_question_summary($questionstat)) {
|
||||
if ($this->is_calculated_question_summary($questionstat)) {
|
||||
return '';
|
||||
}
|
||||
if (!isset($questionstat->question->number)) {
|
||||
@ -164,7 +165,7 @@ class quiz_statistics_table extends flexible_table {
|
||||
* @return string contents of this table cell.
|
||||
*/
|
||||
protected function col_icon($questionstat) {
|
||||
if ($this->is_random_question_summary($questionstat)) {
|
||||
if ($this->is_calculated_question_summary($questionstat)) {
|
||||
return '';
|
||||
} else {
|
||||
return print_question_icon($questionstat->question, true);
|
||||
@ -177,7 +178,7 @@ class quiz_statistics_table extends flexible_table {
|
||||
* @return string contents of this table cell.
|
||||
*/
|
||||
protected function col_actions($questionstat) {
|
||||
if ($this->is_random_question_summary($questionstat)) {
|
||||
if ($this->is_calculated_question_summary($questionstat)) {
|
||||
return '';
|
||||
} else {
|
||||
return quiz_question_action_icons($this->quiz, $this->cmid,
|
||||
@ -241,22 +242,14 @@ class quiz_statistics_table extends flexible_table {
|
||||
$number = $questionstat->question->number;
|
||||
$israndomquestion = $questionstat->question->qtype == 'random';
|
||||
$url = new moodle_url($baseurl, array('slot' => $questionstat->slot));
|
||||
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('viewanalysis', 'quiz_statistics'),
|
||||
array('title' => get_string('viewanalysishint', '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,
|
||||
array('title' => get_string('slotstructureanalysis', 'quiz_statistics', $number)));
|
||||
} else {
|
||||
|
||||
if ($this->is_calculated_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 and variant question rows will render the name without a link to improve clarity
|
||||
// in the UI.
|
||||
$name = html_writer::link($url, get_string('viewanalysis', 'quiz_statistics'));
|
||||
} else if (!$israndomquestion && !$questionstat->get_variants() && !$questionstat->get_sub_question_ids()) {
|
||||
// Question cannot be broken down into sub-questions or variants. Link will show response analysis page.
|
||||
$name = html_writer::link($url,
|
||||
$name,
|
||||
@ -284,7 +277,7 @@ 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)) {
|
||||
if ($this->is_calculated_question_summary($questionstat)) {
|
||||
list($min, $max) = $questionstat->get_min_max_of('s');
|
||||
$a = new stdClass();
|
||||
$a->min = $min ?: 0;
|
||||
@ -303,7 +296,7 @@ class quiz_statistics_table extends flexible_table {
|
||||
* @return string contents of this table cell.
|
||||
*/
|
||||
protected function col_facility($questionstat) {
|
||||
if ($this->is_random_question_summary($questionstat)) {
|
||||
if ($this->is_calculated_question_summary($questionstat)) {
|
||||
list($min, $max) = $questionstat->get_min_max_of('facility');
|
||||
|
||||
if (is_null($min) && is_null($max)) {
|
||||
@ -327,7 +320,7 @@ class quiz_statistics_table extends flexible_table {
|
||||
* @return string contents of this table cell.
|
||||
*/
|
||||
protected function col_sd($questionstat) {
|
||||
if ($this->is_random_question_summary($questionstat)) {
|
||||
if ($this->is_calculated_question_summary($questionstat)) {
|
||||
list($min, $max) = $questionstat->get_min_max_of('sd');
|
||||
|
||||
if (is_null($min) && is_null($max)) {
|
||||
@ -351,7 +344,7 @@ class quiz_statistics_table extends flexible_table {
|
||||
* @return string contents of this table cell.
|
||||
*/
|
||||
protected function col_random_guess_score($questionstat) {
|
||||
if ($this->is_random_question_summary($questionstat)) {
|
||||
if ($this->is_calculated_question_summary($questionstat)) {
|
||||
list($min, $max) = $questionstat->get_min_max_of('randomguessscore');
|
||||
|
||||
if (is_null($min) && is_null($max)) {
|
||||
@ -378,7 +371,7 @@ 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)) {
|
||||
if ($this->is_calculated_question_summary($questionstat)) {
|
||||
list($min, $max) = $questionstat->get_min_max_of('maxmark');
|
||||
|
||||
if (is_null($min) && is_null($max)) {
|
||||
@ -403,7 +396,7 @@ class quiz_statistics_table extends flexible_table {
|
||||
protected function col_effective_weight($questionstat) {
|
||||
global $OUTPUT;
|
||||
|
||||
if ($this->is_random_question_summary($questionstat)) {
|
||||
if ($this->is_calculated_question_summary($questionstat)) {
|
||||
list($min, $max) = $questionstat->get_min_max_of('effectiveweight');
|
||||
|
||||
if (is_null($min) && is_null($max)) {
|
||||
@ -444,7 +437,7 @@ class quiz_statistics_table extends flexible_table {
|
||||
* @return string contents of this table cell.
|
||||
*/
|
||||
protected function col_discrimination_index($questionstat) {
|
||||
if ($this->is_random_question_summary($questionstat)) {
|
||||
if ($this->is_calculated_question_summary($questionstat)) {
|
||||
list($min, $max) = $questionstat->get_min_max_of('discriminationindex');
|
||||
|
||||
if (is_numeric($min)) {
|
||||
@ -472,7 +465,7 @@ class quiz_statistics_table extends flexible_table {
|
||||
* @return string contents of this table cell.
|
||||
*/
|
||||
protected function col_discriminative_efficiency($questionstat) {
|
||||
if ($this->is_random_question_summary($questionstat)) {
|
||||
if ($this->is_calculated_question_summary($questionstat)) {
|
||||
list($min, $max) = $questionstat->get_min_max_of('discriminativeefficiency');
|
||||
|
||||
if (!is_numeric($min) && !is_numeric($max)) {
|
||||
@ -496,7 +489,7 @@ class quiz_statistics_table extends flexible_table {
|
||||
* @return bool is this question possibly not pulling it's weight?
|
||||
*/
|
||||
protected function is_dubious_question($questionstat) {
|
||||
if ($this->is_random_question_summary($questionstat)) {
|
||||
if ($this->is_calculated_question_summary($questionstat)) {
|
||||
// We only care about the minimum value here.
|
||||
// If the minimum value is less than the threshold, then we know that there is at least one value below the threshold.
|
||||
list($discriminativeefficiency) = $questionstat->get_min_max_of('discriminativeefficiency');
|
||||
@ -512,13 +505,13 @@ class quiz_statistics_table extends flexible_table {
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given stats object is an instance of calculated_random_question_summary.
|
||||
* Check if the given stats object is an instance of calculated_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;
|
||||
protected function is_calculated_question_summary($questionstat) {
|
||||
return $questionstat instanceof calculated_question_summary;
|
||||
}
|
||||
|
||||
public function wrap_html_start() {
|
||||
|
@ -39,12 +39,6 @@ class all_calculated_for_qubaid_condition {
|
||||
/** @var int Time after which statistics are automatically recomputed. */
|
||||
const TIME_TO_CACHE = 900; // 15 minutes.
|
||||
|
||||
/**
|
||||
* The limit of rows of sub-question and variants rows to display on main page of report before switching to showing min,
|
||||
* median and max variants.
|
||||
*/
|
||||
const SUBQ_AND_VARIANT_ROW_LIMIT = 10;
|
||||
|
||||
/**
|
||||
* @var object[]
|
||||
*/
|
||||
@ -311,16 +305,6 @@ class all_calculated_for_qubaid_condition {
|
||||
return $errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Are there too many rows of sub-questions and / or variant rows.
|
||||
*
|
||||
* @param array $rows the rows we intend to add.
|
||||
* @return bool Are there too many?
|
||||
*/
|
||||
protected function too_many_subq_and_or_variant_rows($rows) {
|
||||
return (count($rows) > static::SUBQ_AND_VARIANT_ROW_LIMIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* From a number of calculated instances find the three instances with min, median and maximum facility index values.
|
||||
*
|
||||
@ -405,7 +389,7 @@ class all_calculated_for_qubaid_condition {
|
||||
*
|
||||
* @param int $slot the slot no
|
||||
* @param bool $limited limit number of variants and sub-questions displayed?
|
||||
* @return calculated|calculated_for_subquestion|calculated_random_question_summary[] stats to display
|
||||
* @return calculated|calculated_for_subquestion|calculated_question_summary[] stats to display
|
||||
*/
|
||||
protected function all_subq_and_variant_stats_for_slot($slot, $limited) {
|
||||
// Random question in this slot?
|
||||
@ -416,20 +400,26 @@ class all_calculated_for_qubaid_condition {
|
||||
$randomquestioncalculated = $this->for_slot($slot);
|
||||
|
||||
if ($subqvariantstats = $this->all_subq_variants_for_one_slot($slot)) {
|
||||
// There are some variants from randomly selected questions.
|
||||
$subqvariantfacilitystats = $this->find_min_median_and_max_facility_stats_objects($subqvariantstats);
|
||||
$toreturn = array_merge($toreturn, $subqvariantfacilitystats);
|
||||
|
||||
// If we're showing a limited view of the statistics then add a question summary stat
|
||||
// rather than a stat for each subquestion.
|
||||
$summarystat = $this->make_new_calculated_question_summary_stat($randomquestioncalculated, $subqvariantstats);
|
||||
|
||||
$toreturn = array_merge($toreturn, [$summarystat], $subqvariantfacilitystats);
|
||||
}
|
||||
|
||||
if ($subqstats = $this->all_subqs_for_one_slot($slot)) {
|
||||
// There are some randomly selected questions.
|
||||
$subqfacilitystats = $this->find_min_median_and_max_facility_stats_objects($subqstats);
|
||||
$toreturn = array_merge($toreturn, $subqfacilitystats);
|
||||
}
|
||||
|
||||
// If we're showing a limited view of the statistics then add a
|
||||
// random question summary stat rather than a stat for each
|
||||
// subquestion.
|
||||
$summarystat = $this->make_new_random_question_summary_stat($randomquestioncalculated, $subqstats);
|
||||
$toreturn = array_merge([$summarystat], $toreturn);
|
||||
// If we're showing a limited view of the statistics then add a question summary stat
|
||||
// rather than a stat for each subquestion.
|
||||
$summarystat = $this->make_new_calculated_question_summary_stat($randomquestioncalculated, $subqstats);
|
||||
|
||||
$toreturn = array_merge($toreturn, [$summarystat], $subqfacilitystats);
|
||||
}
|
||||
|
||||
foreach ($toreturn as $index => $calculated) {
|
||||
$calculated->subqdisplayorder = $index;
|
||||
@ -450,8 +440,15 @@ class all_calculated_for_qubaid_condition {
|
||||
return $toreturn;
|
||||
} else {
|
||||
$variantstats = $this->all_variant_stats_for_one_slot($slot);
|
||||
if ($limited && $this->too_many_subq_and_or_variant_rows($variantstats)) {
|
||||
return $this->find_min_median_and_max_facility_stats_objects($variantstats);
|
||||
if ($limited && $variantstats) {
|
||||
$variantquestioncalculated = $this->for_slot($slot);
|
||||
$variantfacilitystats = $this->find_min_median_and_max_facility_stats_objects($variantstats);
|
||||
|
||||
// If we're showing a limited view of the statistics then add a question summary stat
|
||||
// rather than a stat for each variation.
|
||||
$summarystat = $this->make_new_calculated_question_summary_stat($variantquestioncalculated, $variantstats);
|
||||
|
||||
return array_merge([$summarystat], $variantfacilitystats);
|
||||
} else {
|
||||
return $variantstats;
|
||||
}
|
||||
@ -476,18 +473,18 @@ class all_calculated_for_qubaid_condition {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* Create a summary calculated object for a calculated question. This is used as a placeholder
|
||||
* to indicate that a calculated question has sub questions or variations to show rather than listing each
|
||||
* subquestion or variation directly.
|
||||
*
|
||||
* @param calculated $randomquestioncalculated The calculated instance for the random question slot.
|
||||
* @param calculated[] $subquestionstats The instances of the calculated stats of the questions that are being summarised.
|
||||
* @return calculated_random_question_summary
|
||||
* @return calculated_question_summary
|
||||
*/
|
||||
protected function make_new_random_question_summary_stat($randomquestioncalculated, $subquestionstats) {
|
||||
protected function make_new_calculated_question_summary_stat($randomquestioncalculated, $subquestionstats) {
|
||||
$question = $randomquestioncalculated->question;
|
||||
$slot = $randomquestioncalculated->slot;
|
||||
$calculatedsummary = new calculated_random_question_summary($question, $slot, $subquestionstats);
|
||||
$calculatedsummary = new calculated_question_summary($question, $slot, $subquestionstats);
|
||||
|
||||
return $calculatedsummary;
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ namespace core_question\statistics\questions;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Class calculated_random_question_summary
|
||||
* Class calculated_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.
|
||||
@ -37,7 +37,7 @@ defined('MOODLE_INTERNAL') || die();
|
||||
* @copyright 2018 Ryan Wyllie <ryan@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class calculated_random_question_summary extends calculated {
|
||||
class calculated_question_summary extends calculated {
|
||||
|
||||
/**
|
||||
* @var int only set immediately before display in the table. The order of display in the table.
|
||||
@ -50,7 +50,7 @@ class calculated_random_question_summary extends calculated {
|
||||
protected $subqstats;
|
||||
|
||||
/**
|
||||
* calculated_random_question_summary constructor.
|
||||
* calculated_question_summary constructor.
|
||||
*
|
||||
* @param \stdClass $question
|
||||
* @param int $slot
|
@ -25,15 +25,15 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use core_question\statistics\questions\calculated_random_question_summary;
|
||||
use core_question\statistics\questions\calculated_question_summary;
|
||||
|
||||
/**
|
||||
* Class core_question_calculated_random_question_summary_testcase
|
||||
* Class core_question_calculated_question_summary_testcase
|
||||
*
|
||||
* @copyright 2018 Shamim Rezaie <shamim@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class core_question_calculated_random_question_summary_testcase extends advanced_testcase {
|
||||
class core_question_calculated_question_summary_testcase extends advanced_testcase {
|
||||
|
||||
/**
|
||||
* Provider for test_get_min_max_of.
|
||||
@ -100,7 +100,7 @@ class core_question_calculated_random_question_summary_testcase extends advanced
|
||||
* @dataProvider get_min_max_provider
|
||||
*/
|
||||
public function test_get_min_max_of($subqstats, $expected) {
|
||||
$calculatedsummary = new calculated_random_question_summary(null, null, $subqstats);
|
||||
$calculatedsummary = new calculated_question_summary(null, null, $subqstats);
|
||||
$res = $calculatedsummary->get_min_max_of('index');
|
||||
$this->assertEquals($expected, $res);
|
||||
}
|
||||
@ -151,7 +151,7 @@ class core_question_calculated_random_question_summary_testcase extends advanced
|
||||
* @dataProvider get_sd_min_max_provider
|
||||
*/
|
||||
public function test_get_min_max_of_sd($subqstats, $expected) {
|
||||
$calculatedsummary = new calculated_random_question_summary(null, null, $subqstats);
|
||||
$calculatedsummary = new calculated_question_summary(null, null, $subqstats);
|
||||
$res = $calculatedsummary->get_min_max_of('sd');
|
||||
$this->assertEquals($expected, $res);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user