MDL-41754 (2) quiz statistics : using Sam's new progress classes
[moodle.git] / mod / quiz / report / statistics / classes / calculated.php
CommitLineData
7de1e35b
JP
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
8da6fc9d
JP
17namespace quiz_statistics;
18
19defined('MOODLE_INTERNAL') || die();
20
7de1e35b
JP
21/**
22 * The statistics calculator returns an instance of this class which contains the calculated statistics.
23 *
522bef80
JP
24 * These quiz statistics calculations are described here :
25 *
26 * http://docs.moodle.org/dev/Quiz_statistics_calculations#Test_statistics
27 *
7de1e35b
JP
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 */
8da6fc9d 33class calculated {
7de1e35b 34
6dd9362e
JP
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;
7de1e35b
JP
46 }
47 }
48
49 /**
6dd9362e 50 * @var int which attempts we are calculating calculate stats from.
7de1e35b 51 */
6dd9362e 52 public $whichattempts;
7de1e35b 53
522bef80
JP
54 /* Following stats all described here : http://docs.moodle.org/dev/Quiz_statistics_calculations#Test_statistics */
55
7de1e35b
JP
56 public $firstattemptscount = 0;
57
58 public $allattemptscount = 0;
59
6dd9362e
JP
60 public $lastattemptscount = 0;
61
62 public $highestattemptscount = 0;
63
7de1e35b
JP
64 public $firstattemptsavg;
65
66 public $allattemptsavg;
67
6dd9362e
JP
68 public $lastattemptsavg;
69
70 public $highestattemptsavg;
71
7de1e35b
JP
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
522bef80
JP
86 /**
87 * @var int time these stats where calculated and cached.
88 */
7de1e35b
JP
89 public $timemodified;
90
6dd9362e
JP
91 /**
92 * Count of attempts selected by $this->whichattempts
93 *
94 * @return int
95 */
7de1e35b 96 public function s() {
6dd9362e 97 return $this->get_field('count');
7de1e35b
JP
98 }
99
6dd9362e
JP
100 /**
101 * Average grade for the attempts selected by $this->whichattempts
102 *
103 * @return float
104 */
7de1e35b 105 public function avg() {
6dd9362e
JP
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) {
8da6fc9d 117 $fieldname = calculator::using_attempts_string_id($this->whichattempts).$field;
6dd9362e 118 return $this->{$fieldname};
7de1e35b
JP
119 }
120
7de1e35b
JP
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 = array('firstattemptscount' => 'number',
131 'allattemptscount' => 'number',
132 'firstattemptsavg' => 'summarks_as_percentage',
133 'allattemptsavg' => 'summarks_as_percentage',
6dd9362e
JP
134 'lastattemptsavg' => 'summarks_as_percentage',
135 'highestattemptsavg' => 'summarks_as_percentage',
7de1e35b
JP
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 = array();
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) {
933ac749 164 if (!isset($this->$property) || !$format) {
7de1e35b
JP
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
6dd9362e 188 $quizinfo[get_string($property, 'quiz_statistics',
8da6fc9d 189 calculator::using_attempts_lang_string($this->whichattempts))] = $formattedvalue;
7de1e35b
JP
190 }
191
192 return $quizinfo;
193 }
194
522bef80
JP
195 /**
196 * @var array of names of properties of this class that are cached in db record.
197 */
6dd9362e
JP
198 protected $fieldsindb = array('whichattempts', 'firstattemptscount', 'allattemptscount', 'firstattemptsavg', 'allattemptsavg',
199 'lastattemptscount', 'highestattemptscount', 'lastattemptsavg', 'highestattemptsavg',
7de1e35b
JP
200 'median', 'standarddeviation', 'skewness',
201 'kurtosis', 'cic', 'errorratio', 'standarderror');
202
203 /**
522bef80
JP
204 * Cache the stats contained in this class.
205 *
8da6fc9d 206 * @param $qubaids \qubaid_condition
7de1e35b
JP
207 */
208 public function cache($qubaids) {
209 global $DB;
210
8da6fc9d 211 $toinsert = new \stdClass();
7de1e35b
JP
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 // Store the data.
229 $DB->insert_record('quiz_statistics', $toinsert);
230
231 }
232
522bef80
JP
233 /**
234 * Given a record from 'quiz_statistics' table load the data into the properties of this class.
235 *
8da6fc9d 236 * @param $record \stdClass from db.
522bef80 237 */
7de1e35b
JP
238 public function populate_from_record($record) {
239 foreach ($this->fieldsindb as $field) {
240 $this->$field = $record->$field;
241 }
242 $this->timemodified = $record->timemodified;
243 }
244}