MDL-20636 Eliminate integer and boolean in PHPdoc comments. should be int and bool.
[moodle.git] / question / engine / states.php
CommitLineData
d1b7e03d
TH
1<?php
2
3// This file is part of Moodle - http://moodle.org/
4//
5// Moodle is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// Moodle is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
17
d1b7e03d
TH
18/**
19 * This defines the states a question can be in.
20 *
017bc1d9 21 * @package moodlecore
d1b7e03d 22 * @subpackage questionengine
017bc1d9
TH
23 * @copyright 2010 The Open University
24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
d1b7e03d
TH
25 */
26
27
a17b297d
TH
28defined('MOODLE_INTERNAL') || die();
29
30
d1b7e03d
TH
31/**
32 * An enumeration representing the states a question can be in after a
33 * {@link question_attempt_step}.
34 *
35 * There are also some useful methods for testing and manipulating states.
36 *
017bc1d9
TH
37 * @copyright 2009 The Open University
38 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
d1b7e03d 39 */
d1b7e03d
TH
40abstract class question_state {
41 /**#@+
42 * Specific question_state instances.
43 */
44 public static $notstarted;
45 public static $unprocessed;
46 public static $todo;
47 public static $invalid;
48 public static $complete;
49 public static $needsgrading;
50 public static $finished;
51 public static $gaveup;
52 public static $gradedwrong;
53 public static $gradedpartial;
54 public static $gradedright;
55 public static $manfinished;
56 public static $mangaveup;
57 public static $mangrwrong;
58 public static $mangrpartial;
59 public static $mangrright;
60 /**#@+-*/
61
62 protected function __construct() {
63 }
64
65 public static function init() {
66 $us = new ReflectionClass('question_state');
67 foreach ($us->getStaticProperties() as $name => $notused) {
68 $class = 'question_state_' . $name;
69 $states[$name] = new $class();
70 self::$$name = $states[$name];
71 }
72 }
73
74 /**
75 * Get all the states in an array.
76 * @return of question_state objects.
77 */
78 public static function get_all() {
79 $states = array();
80 $us = new ReflectionClass('question_state');
81 foreach ($us->getStaticProperties() as $name => $notused) {
82 $states[] = self::$$name;
83 }
84 return $states;
85 }
86
87 /**
88 * Get all the states in an array.
89 * @param string $summarystate one of the four summary states
90 * inprogress, needsgrading, manuallygraded or autograded.
91 * @return arrau of the corresponding states.
92 */
93 public static function get_all_for_summary_state($summarystate) {
94 $states = array();
95 foreach (self::get_all() as $state) {
96 if ($state->get_summary_state() == $summarystate) {
97 $states[] = $state;
98 }
99 }
100 if (empty($states)) {
101 throw new Exception('unknown summary state ' . $summarystate);
102 }
103 return $states;
104 }
105
106 /**
107 * @return string convert this state to a string.
108 */
109 public function __toString() {
110 return substr(get_class($this), 15);
111 }
112
113 /**
114 * @param string $name a state name.
115 * @return question_state the state with that name.
116 */
117 public static function get($name) {
118 return self::$$name;
119 }
120
121 /**
122 * Is this state one of the ones that mean the question attempt is in progress?
123 * That is, started, but no finished.
f7970e3c 124 * @return bool
d1b7e03d
TH
125 */
126 public function is_active() {
127 return false;
128 }
129
130 /**
131 * Is this state one of the ones that mean the question attempt is finished?
132 * That is, no further interaction possible, apart from manual grading.
f7970e3c 133 * @return bool
d1b7e03d
TH
134 */
135 public function is_finished() {
136 return true;
137 }
138
139 /**
140 * Is this state one of the ones that mean the question attempt has been graded?
f7970e3c 141 * @return bool
d1b7e03d
TH
142 */
143 public function is_graded() {
144 return false;
145 }
146
147 /**
148 * Is this state one of the ones that mean the question attempt has been graded?
f7970e3c 149 * @return bool
d1b7e03d
TH
150 */
151 public function is_correct() {
152 return false;
153 }
154
155 /**
156 * Is this state one of the ones that mean the question attempt has been graded?
f7970e3c 157 * @return bool
d1b7e03d
TH
158 */
159 public function is_partially_correct() {
160 return false;
161 }
162
163 /**
164 * Is this state one of the ones that mean the question attempt has been graded?
f7970e3c 165 * @return bool
d1b7e03d
TH
166 */
167 public function is_incorrect() {
168 return false;
169 }
170
171 /**
172 * Is this state one of the ones that mean the question attempt has been graded?
f7970e3c 173 * @return bool
d1b7e03d
TH
174 */
175 public function is_gave_up() {
176 return false;
177 }
178
179 /**
180 * Is this state one of the ones that mean the question attempt has had a manual comment added?
f7970e3c 181 * @return bool
d1b7e03d
TH
182 */
183 public function is_commented() {
184 return false;
185 }
186
187 /**
188 * Each state can be categorised into one of four categories:
189 * inprogress, needsgrading, manuallygraded or autograded.
190 * @return string which category this state falls into.
191 */
192 public function get_summary_state() {
193 if (!$this->is_finished()) {
194 return 'inprogress';
195 } else if ($this == self::$needsgrading) {
196 return 'needsgrading';
197 } else if ($this->is_commented()) {
198 return 'manuallygraded';
199 } else {
200 return 'autograded';
201 }
202 }
203
204 /**
205 * Return the appropriate graded state based on a fraction. That is 0 or less
206 * is $graded_incorrect, 1 is $graded_correct, otherwise it is $graded_partcorrect.
207 * Appropriate allowance is made for rounding float values.
208 *
209 * @param number $fraction the grade, on the fraction scale.
f7970e3c 210 * @return int one of the state constants.
d1b7e03d
TH
211 */
212 public static function graded_state_for_fraction($fraction) {
213 if ($fraction < 0.000001) {
214 return self::$gradedwrong;
215 } else if ($fraction > 0.999999) {
216 return self::$gradedright;
217 } else {
218 return self::$gradedpartial;
219 }
220 }
221
222 /**
223 * Return the appropriate manually graded state based on a fraction. That is 0 or less
224 * is $manually_graded_incorrect, 1 is $manually_graded_correct, otherwise it is
225 * $manually_graded_partcorrect. Appropriate allowance is made for rounding float values.
226 *
227 * @param number $fraction the grade, on the fraction scale.
f7970e3c 228 * @return int one of the state constants.
d1b7e03d
TH
229 */
230 public static function manually_graded_state_for_fraction($fraction) {
231 if (is_null($fraction)) {
232 return self::$needsgrading;
233 } else if ($fraction < 0.000001) {
234 return self::$mangrwrong;
235 } else if ($fraction > 0.999999) {
236 return self::$mangrright;
237 } else {
238 return self::$mangrpartial;
239 }
240 }
241
242 /**
243 * Compute an appropriate state to move to after a manual comment has been
244 * added to this state.
245 * @param number $fraction the manual grade (if any) on the fraction scale.
f7970e3c 246 * @return int the new state.
d1b7e03d
TH
247 */
248 public function corresponding_commented_state($fraction) {
249 throw new Exception('Unexpected question state.');
250 }
251
252 /**
253 * Return an appropriate CSS class name ''/'correct'/'partiallycorrect'/'incorrect',
254 * for a state.
255 * @return string
256 */
257 public function get_feedback_class() {
258 return '';
259 }
260
261 /**
262 * Return the name of an appropriate string to look up in the question
263 * language pack for a state. This is used, for example, by
264 * {@link question_behaviour::get_state_string()}. However, behaviours
265 * sometimes change this default string for soemthing more specific.
266 *
f7970e3c 267 * @param bool $showcorrectness Whether right/partial/wrong states should
d1b7e03d
TH
268 * be distinguised, or just treated as 'complete'.
269 * @return string the name of a string that can be looked up in the 'question'
270 * lang pack, or used as a CSS class name, etc.
271 */
272 public abstract function get_state_class($showcorrectness);
273
274 /**
275 * The result of doing get_string on the result of {@link get_state_class()}.
276 *
f7970e3c 277 * @param bool $showcorrectness Whether right/partial/wrong states should
d1b7e03d
TH
278 * be distinguised.
279 * @return string a string from the lang pack that can be used in the UI.
280 */
281 public function default_string($showcorrectness) {
282 return get_string($this->get_state_class($showcorrectness), 'question');
283 }
284}
285
286
287/**#@+
288 * Specific question_state subclasses.
289 *
017bc1d9
TH
290 * @copyright 2009 The Open University
291 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
d1b7e03d
TH
292 */
293class question_state_notstarted extends question_state {
294 public function is_finished() {
295 return false;
296 }
297 public function get_state_class($showcorrectness) {
298 throw new Exception('Unexpected question state.');
299 }
300}
301class question_state_unprocessed extends question_state {
302 public function is_finished() {
303 return false;
304 }
305 public function get_state_class($showcorrectness) {
306 throw new Exception('Unexpected question state.');
307 }
308}
309class question_state_todo extends question_state {
310 public function is_active() {
311 return true;
312 }
313 public function is_finished() {
314 return false;
315 }
316 public function get_state_class($showcorrectness) {
317 return 'notyetanswered';
318 }
319}
320class question_state_invalid extends question_state {
321 public function is_active() {
322 return true;
323 }
324 public function is_finished() {
325 return false;
326 }
327 public function get_state_class($showcorrectness) {
328 return 'invalidanswer';
329 }
330}
331class question_state_complete extends question_state {
332 public function is_active() {
333 return true;
334 }
335 public function is_finished() {
336 return false;
337 }
338 public function get_state_class($showcorrectness) {
339 return 'answersaved';
340 }
341}
342class question_state_needsgrading extends question_state {
343 public function get_state_class($showcorrectness) {
f86390dc
TH
344 if ($showcorrectness) {
345 return 'requiresgrading';
346 } else {
347 return 'complete';
348 }
d1b7e03d
TH
349 }
350 public function corresponding_commented_state($fraction) {
351 return self::manually_graded_state_for_fraction($fraction);
352 }
353}
354class question_state_finished extends question_state {
355 public function get_state_class($showcorrectness) {
356 return 'complete';
357 }
358 public function corresponding_commented_state($fraction) {
359 return self::$manfinished;
360 }
361}
362class question_state_gaveup extends question_state {
363 public function is_gave_up() {
364 return true;
365 }
366 public function get_feedback_class() {
367 return 'incorrect';
368 }
369 public function get_state_class($showcorrectness) {
370 return 'notanswered';
371 }
372 public function corresponding_commented_state($fraction) {
373 if (is_null($fraction)) {
374 return self::$mangaveup;
375 } else {
376 return self::manually_graded_state_for_fraction($fraction);
377 }
378 }
379}
380abstract class question_state_graded extends question_state {
381 public function is_graded() {
382 return true;
383 }
384 public function get_state_class($showcorrectness) {
385 if ($showcorrectness) {
386 return $this->get_feedback_class();
387 } else {
388 return 'complete';
389 }
390 }
391 public function corresponding_commented_state($fraction) {
392 return self::manually_graded_state_for_fraction($fraction);
393 }
394}
395class question_state_gradedwrong extends question_state_graded {
396 public function is_incorrect() {
397 return true;
398 }
399 public function get_feedback_class() {
400 return 'incorrect';
401 }
402}
403class question_state_gradedpartial extends question_state_graded {
404 public function is_graded() {
405 return true;
406 }
407 public function is_partially_correct() {
408 return true;
409 }
410 public function get_feedback_class() {
411 return 'partiallycorrect';
412 }
413}
414class question_state_gradedright extends question_state_graded {
415 public function is_graded() {
416 return true;
417 }
418 public function is_correct() {
419 return true;
420 }
421 public function get_feedback_class() {
422 return 'correct';
423 }
424}
425class question_state_manfinished extends question_state_finished {
426 public function is_commented() {
427 return true;
428 }
429}
430class question_state_mangaveup extends question_state_gaveup {
431 public function is_commented() {
432 return true;
433 }
434}
435abstract class question_state_manuallygraded extends question_state_graded {
436 public function is_commented() {
437 return true;
438 }
439}
440class question_state_mangrwrong extends question_state_manuallygraded {
441 public function is_incorrect() {
442 return false;
443 }
444 public function get_feedback_class() {
445 return 'incorrect';
446 }
447}
448class question_state_mangrpartial extends question_state_manuallygraded {
449 public function is_partially_correct() {
450 return true;
451 }
452 public function get_feedback_class() {
453 return 'partiallycorrect';
454 }
455}
456class question_state_mangrright extends question_state_manuallygraded {
457 public function is_correct() {
458 return true;
459 }
460 public function get_feedback_class() {
461 return 'correct';
462 }
463}
464/**#@-*/
465question_state::init();