Differences Between: [Versions 310 and 403] [Versions 311 and 403] [Versions 39 and 403] [Versions 400 and 403] [Versions 401 and 403]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 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. 8 // 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. 13 // 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/>. 16 17 namespace quiz_statistics; 18 19 defined('MOODLE_INTERNAL') || die(); 20 21 /** 22 * The statistics calculator returns an instance of this class which contains the calculated statistics. 23 * 24 * These quiz statistics calculations are described here : 25 * 26 * http://docs.moodle.org/dev/Quiz_statistics_calculations#Test_statistics 27 * 28 * @package quiz_statistics 29 * @copyright 2013 The Open University 30 * @author James Pratt me@jamiep.org 31 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 32 */ 33 class calculated { 34 35 /** 36 * @param string $whichattempts which attempts to use, represented internally as one of the constants as used in 37 * $quiz->grademethod ie. 38 * QUIZ_GRADEAVERAGE, QUIZ_GRADEHIGHEST, QUIZ_ATTEMPTLAST or QUIZ_ATTEMPTFIRST 39 * we calculate stats based on which attempts would affect the grade for each student, 40 * the default null value is used when constructing an instance whose values will be 41 * populated from a db record. 42 */ 43 public function __construct($whichattempts = null) { 44 if ($whichattempts !== null) { 45 $this->whichattempts = $whichattempts; 46 } 47 } 48 49 /** 50 * @var int which attempts we are calculating calculate stats from. 51 */ 52 public $whichattempts; 53 54 /* Following stats all described here : http://docs.moodle.org/dev/Quiz_statistics_calculations#Test_statistics */ 55 56 public $firstattemptscount = 0; 57 58 public $allattemptscount = 0; 59 60 public $lastattemptscount = 0; 61 62 public $highestattemptscount = 0; 63 64 public $firstattemptsavg; 65 66 public $allattemptsavg; 67 68 public $lastattemptsavg; 69 70 public $highestattemptsavg; 71 72 public $median; 73 74 public $standarddeviation; 75 76 public $skewness; 77 78 public $kurtosis; 79 80 public $cic; 81 82 public $errorratio; 83 84 public $standarderror; 85 86 /** 87 * @var int time these stats where calculated and cached. 88 */ 89 public $timemodified; 90 91 /** 92 * Count of attempts selected by $this->whichattempts 93 * 94 * @return int 95 */ 96 public function s() { 97 return $this->get_field('count'); 98 } 99 100 /** 101 * Average grade for the attempts selected by $this->whichattempts 102 * 103 * @return float 104 */ 105 public function avg() { 106 return $this->get_field('avg'); 107 } 108 109 /** 110 * Get the right field name to fetch a stat for these attempts that is calculated for more than one $whichattempts (count or 111 * avg). 112 * 113 * @param string $field name of field 114 * @return int|float 115 */ 116 protected function get_field($field) { 117 $fieldname = calculator::using_attempts_string_id($this->whichattempts).$field; 118 return $this->{$fieldname}; 119 } 120 121 /** 122 * @param $course 123 * @param $cm 124 * @param $quiz 125 * @return array to display in table or spreadsheet. 126 */ 127 public function get_formatted_quiz_info_data($course, $cm, $quiz) { 128 129 // You can edit this array to control which statistics are displayed. 130 $todisplay = ['firstattemptscount' => 'number', 131 'allattemptscount' => 'number', 132 'firstattemptsavg' => 'summarks_as_percentage', 133 'allattemptsavg' => 'summarks_as_percentage', 134 'lastattemptsavg' => 'summarks_as_percentage', 135 'highestattemptsavg' => 'summarks_as_percentage', 136 'median' => 'summarks_as_percentage', 137 'standarddeviation' => 'summarks_as_percentage', 138 'skewness' => 'number_format', 139 'kurtosis' => 'number_format', 140 'cic' => 'number_format_percent', 141 'errorratio' => 'number_format_percent', 142 'standarderror' => 'summarks_as_percentage']; 143 144 // General information about the quiz. 145 $quizinfo = []; 146 $quizinfo[get_string('quizname', 'quiz_statistics')] = format_string($quiz->name); 147 $quizinfo[get_string('coursename', 'quiz_statistics')] = format_string($course->fullname); 148 if ($cm->idnumber) { 149 $quizinfo[get_string('idnumbermod')] = $cm->idnumber; 150 } 151 if ($quiz->timeopen) { 152 $quizinfo[get_string('quizopen', 'quiz')] = userdate($quiz->timeopen); 153 } 154 if ($quiz->timeclose) { 155 $quizinfo[get_string('quizclose', 'quiz')] = userdate($quiz->timeclose); 156 } 157 if ($quiz->timeopen && $quiz->timeclose) { 158 $quizinfo[get_string('duration', 'quiz_statistics')] = 159 format_time($quiz->timeclose - $quiz->timeopen); 160 } 161 162 // The statistics. 163 foreach ($todisplay as $property => $format) { 164 if (!isset($this->$property) || !$format) { 165 continue; 166 } 167 $value = $this->$property; 168 169 switch ($format) { 170 case 'summarks_as_percentage': 171 $formattedvalue = quiz_report_scale_summarks_as_percentage($value, $quiz); 172 break; 173 case 'number_format_percent': 174 $formattedvalue = quiz_format_grade($quiz, $value) . '%'; 175 break; 176 case 'number_format': 177 // 2 extra decimal places, since not a percentage, 178 // and we want the same number of sig figs. 179 $formattedvalue = format_float($value, $quiz->decimalpoints + 2); 180 break; 181 case 'number': 182 $formattedvalue = $value + 0; 183 break; 184 default: 185 $formattedvalue = $value; 186 } 187 188 $quizinfo[get_string($property, 'quiz_statistics', 189 calculator::using_attempts_lang_string($this->whichattempts))] = $formattedvalue; 190 } 191 192 return $quizinfo; 193 } 194 195 /** 196 * @var array of names of properties of this class that are cached in db record. 197 */ 198 protected $fieldsindb = ['whichattempts', 'firstattemptscount', 'allattemptscount', 'firstattemptsavg', 'allattemptsavg', 199 'lastattemptscount', 'highestattemptscount', 'lastattemptsavg', 'highestattemptsavg', 200 'median', 'standarddeviation', 'skewness', 201 'kurtosis', 'cic', 'errorratio', 'standarderror']; 202 203 /** 204 * Cache the stats contained in this class. 205 * 206 * @param $qubaids \qubaid_condition 207 */ 208 public function cache($qubaids) { 209 global $DB; 210 211 $toinsert = new \stdClass(); 212 213 foreach ($this->fieldsindb as $field) { 214 $toinsert->{$field} = $this->{$field}; 215 } 216 217 $toinsert->hashcode = $qubaids->get_hash_code(); 218 $toinsert->timemodified = time(); 219 220 // Fix up some dodgy data. 221 if (isset($toinsert->errorratio) && is_nan($toinsert->errorratio)) { 222 $toinsert->errorratio = null; 223 } 224 if (isset($toinsert->standarderror) && is_nan($toinsert->standarderror)) { 225 $toinsert->standarderror = null; 226 } 227 228 // Delete older statistics before we save the new ones. 229 $transaction = $DB->start_delegated_transaction(); 230 $DB->delete_records('quiz_statistics', ['hashcode' => $qubaids->get_hash_code()]); 231 232 // Store the data. 233 $DB->insert_record('quiz_statistics', $toinsert); 234 $transaction->allow_commit(); 235 } 236 237 /** 238 * Given a record from 'quiz_statistics' table load the data into the properties of this class. 239 * 240 * @param $record \stdClass from db. 241 */ 242 public function populate_from_record($record) { 243 foreach ($this->fieldsindb as $field) { 244 $this->$field = $record->$field; 245 } 246 $this->timemodified = $record->timemodified; 247 } 248 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body