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