See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401]
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 * This defines the states a question can be in. 19 * 20 * @package moodlecore 21 * @subpackage questionengine 22 * @copyright 2010 The Open University 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 26 27 defined('MOODLE_INTERNAL') || die(); 28 29 30 /** 31 * An enumeration representing the states a question can be in after a 32 * {@link question_attempt_step}. 33 * 34 * There are also some useful methods for testing and manipulating states. 35 * 36 * @copyright 2009 The Open University 37 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 38 */ 39 abstract class question_state { 40 /**#@+ 41 * Specific question_state instances. 42 */ 43 public static $notstarted; 44 public static $unprocessed; 45 public static $todo; 46 public static $invalid; 47 public static $complete; 48 public static $needsgrading; 49 public static $finished; 50 public static $gaveup; 51 public static $gradedwrong; 52 public static $gradedpartial; 53 public static $gradedright; 54 public static $manfinished; 55 public static $mangaveup; 56 public static $mangrwrong; 57 public static $mangrpartial; 58 public static $mangrright; 59 /**#@+-*/ 60 61 protected function __construct() { 62 } 63 64 public static function init() { 65 $us = new ReflectionClass('question_state'); 66 foreach ($us->getStaticProperties() as $name => $notused) { 67 $class = 'question_state_' . $name; 68 $states[$name] = new $class(); 69 self::$$name = $states[$name]; 70 } 71 } 72 73 /** 74 * Get all the states in an array. 75 * 76 * @return question_state[] 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 array 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 coding_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 * Get the instance of this class for a given state name. 115 * 116 * @param string $name a state name. 117 * @return question_state|null the state with that name. (Null only in an exceptional case.) 118 */ 119 public static function get(string $name): ?question_state { 120 // In the past, there was a bug where null states got stored 121 // in the database as an empty string, which was wrong because 122 // the state column should be NOT NULL. 123 // That is no longer possible, but we need to avoid exceptions 124 // for people with old bad data in their database. 125 if ($name === '') { 126 debugging('Attempt to create a state from an empty string. ' . 127 'This is probably a sign of bad data in your database. See MDL-80127.'); 128 return null; 129 } 130 131 return self::$$name; 132 } 133 134 /** 135 * Is this state one of the ones that mean the question attempt is in progress? 136 * That is, started, but no finished. 137 * @return bool 138 */ 139 public function is_active() { 140 return false; 141 } 142 143 /** 144 * Is this state one of the ones that mean the question attempt is finished? 145 * That is, no further interaction possible, apart from manual grading. 146 * @return bool 147 */ 148 public function is_finished() { 149 return true; 150 } 151 152 /** 153 * Is this state one of the ones that mean the question attempt has been graded? 154 * @return bool 155 */ 156 public function is_graded() { 157 return false; 158 } 159 160 /** 161 * Is this state one of the ones that mean the question attempt has been graded? 162 * @return bool 163 */ 164 public function is_correct() { 165 return false; 166 } 167 168 /** 169 * Is this state one of the ones that mean the question attempt has been graded? 170 * @return bool 171 */ 172 public function is_partially_correct() { 173 return false; 174 } 175 176 /** 177 * Is this state one of the ones that mean the question attempt has been graded? 178 * @return bool 179 */ 180 public function is_incorrect() { 181 return false; 182 } 183 184 /** 185 * Is this state one of the ones that mean the question attempt has been graded? 186 * @return bool 187 */ 188 public function is_gave_up() { 189 return false; 190 } 191 192 /** 193 * Is this state one of the ones that mean the question attempt has had a manual comment added? 194 * @return bool 195 */ 196 public function is_commented() { 197 return false; 198 } 199 200 /** 201 * Each state can be categorised into one of four categories: 202 * inprogress, needsgrading, manuallygraded or autograded. 203 * @return string which category this state falls into. 204 */ 205 public function get_summary_state() { 206 if (!$this->is_finished()) { 207 return 'inprogress'; 208 } else if ($this == self::$needsgrading) { 209 return 'needsgrading'; 210 } else if ($this->is_commented()) { 211 return 'manuallygraded'; 212 } else { 213 return 'autograded'; 214 } 215 } 216 217 /** 218 * Return the appropriate graded state based on a fraction. That is 0 or less 219 * is $graded_incorrect, 1 is $graded_correct, otherwise it is $graded_partcorrect. 220 * Appropriate allowance is made for rounding float values. 221 * 222 * @param number $fraction the grade, on the fraction scale. 223 * @return question_state one of the state constants. 224 */ 225 public static function graded_state_for_fraction($fraction) { 226 if ($fraction < 0.000001) { 227 return self::$gradedwrong; 228 } else if ($fraction > 0.999999) { 229 return self::$gradedright; 230 } else { 231 return self::$gradedpartial; 232 } 233 } 234 235 /** 236 * Return the appropriate manually graded state based on a fraction. That is 0 or less 237 * is $manually_graded_incorrect, 1 is $manually_graded_correct, otherwise it is 238 * $manually_graded_partcorrect. Appropriate allowance is made for rounding float values. 239 * 240 * @param number $fraction the grade, on the fraction scale. 241 * @return int one of the state constants. 242 */ 243 public static function manually_graded_state_for_fraction($fraction) { 244 if (is_null($fraction)) { 245 return self::$needsgrading; 246 } else if ($fraction < 0.000001) { 247 return self::$mangrwrong; 248 } else if ($fraction > 0.999999) { 249 return self::$mangrright; 250 } else { 251 return self::$mangrpartial; 252 } 253 } 254 255 /** 256 * Compute an appropriate state to move to after a manual comment has been 257 * added to this state. 258 * @param number $fraction the manual grade (if any) on the fraction scale. 259 * @return int the new state. 260 */ 261 public function corresponding_commented_state($fraction) { 262 throw new coding_exception('Unexpected question state.'); 263 } 264 265 /** 266 * Return an appropriate CSS class name ''/'correct'/'partiallycorrect'/'incorrect', 267 * for a state. 268 * @return string 269 */ 270 public function get_feedback_class() { 271 return ''; 272 } 273 274 /** 275 * Return the name of an appropriate string to look up in the question 276 * language pack for a state. This is used, for example, by 277 * {@link question_behaviour::get_state_string()}. However, behaviours 278 * sometimes change this default string for soemthing more specific. 279 * 280 * @param bool $showcorrectness Whether right/partial/wrong states should 281 * be distinguised, or just treated as 'complete'. 282 * @return string the name of a string that can be looked up in the 'question' 283 * lang pack, or used as a CSS class name, etc. 284 */ 285 public abstract function get_state_class($showcorrectness); 286 287 /** 288 * The result of doing get_string on the result of {@link get_state_class()}. 289 * 290 * @param bool $showcorrectness Whether right/partial/wrong states should 291 * be distinguised. 292 * @return string a string from the lang pack that can be used in the UI. 293 */ 294 public function default_string($showcorrectness) { 295 return get_string($this->get_state_class($showcorrectness), 'question'); 296 } 297 } 298 299 300 /**#@+ 301 * Specific question_state subclasses. 302 * 303 * @copyright 2009 The Open University 304 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 305 */ 306 class question_state_notstarted extends question_state { 307 public function is_finished() { 308 return false; 309 } 310 public function get_state_class($showcorrectness) { 311 throw new coding_exception('Unexpected question state.'); 312 } 313 } 314 class question_state_unprocessed extends question_state { 315 public function is_finished() { 316 return false; 317 } 318 public function get_state_class($showcorrectness) { 319 throw new coding_exception('Unexpected question state.'); 320 } 321 } 322 class question_state_todo extends question_state { 323 public function is_active() { 324 return true; 325 } 326 public function is_finished() { 327 return false; 328 } 329 public function get_state_class($showcorrectness) { 330 return 'notyetanswered'; 331 } 332 } 333 class question_state_invalid extends question_state { 334 public function is_active() { 335 return true; 336 } 337 public function is_finished() { 338 return false; 339 } 340 public function get_state_class($showcorrectness) { 341 return 'invalidanswer'; 342 } 343 } 344 class question_state_complete extends question_state { 345 public function is_active() { 346 return true; 347 } 348 public function is_finished() { 349 return false; 350 } 351 public function get_state_class($showcorrectness) { 352 return 'answersaved'; 353 } 354 } 355 class question_state_needsgrading extends question_state { 356 public function get_state_class($showcorrectness) { 357 if ($showcorrectness) { 358 return 'requiresgrading'; 359 } else { 360 return 'complete'; 361 } 362 } 363 public function corresponding_commented_state($fraction) { 364 return self::manually_graded_state_for_fraction($fraction); 365 } 366 } 367 class question_state_finished extends question_state { 368 public function get_state_class($showcorrectness) { 369 return 'complete'; 370 } 371 public function corresponding_commented_state($fraction) { 372 return self::$manfinished; 373 } 374 } 375 class question_state_gaveup extends question_state { 376 public function is_gave_up() { 377 return true; 378 } 379 public function get_feedback_class() { 380 return 'incorrect'; 381 } 382 public function get_state_class($showcorrectness) { 383 return 'notanswered'; 384 } 385 public function corresponding_commented_state($fraction) { 386 if (is_null($fraction)) { 387 return self::$mangaveup; 388 } else { 389 return self::manually_graded_state_for_fraction($fraction); 390 } 391 } 392 } 393 abstract class question_state_graded extends question_state { 394 public function is_graded() { 395 return true; 396 } 397 public function get_state_class($showcorrectness) { 398 if ($showcorrectness) { 399 return $this->get_feedback_class(); 400 } else { 401 return 'complete'; 402 } 403 } 404 public function corresponding_commented_state($fraction) { 405 return self::manually_graded_state_for_fraction($fraction); 406 } 407 } 408 class question_state_gradedwrong extends question_state_graded { 409 public function is_incorrect() { 410 return true; 411 } 412 public function get_feedback_class() { 413 return 'incorrect'; 414 } 415 } 416 class question_state_gradedpartial extends question_state_graded { 417 public function is_graded() { 418 return true; 419 } 420 public function is_partially_correct() { 421 return true; 422 } 423 public function get_feedback_class() { 424 return 'partiallycorrect'; 425 } 426 } 427 class question_state_gradedright extends question_state_graded { 428 public function is_graded() { 429 return true; 430 } 431 public function is_correct() { 432 return true; 433 } 434 public function get_feedback_class() { 435 return 'correct'; 436 } 437 } 438 class question_state_manfinished extends question_state_finished { 439 public function is_commented() { 440 return true; 441 } 442 } 443 class question_state_mangaveup extends question_state_gaveup { 444 public function is_commented() { 445 return true; 446 } 447 } 448 abstract class question_state_manuallygraded extends question_state_graded { 449 public function is_commented() { 450 return true; 451 } 452 } 453 class question_state_mangrwrong extends question_state_manuallygraded { 454 public function is_incorrect() { 455 return false; 456 } 457 public function get_feedback_class() { 458 return 'incorrect'; 459 } 460 } 461 class question_state_mangrpartial extends question_state_manuallygraded { 462 public function is_partially_correct() { 463 return true; 464 } 465 public function get_feedback_class() { 466 return 'partiallycorrect'; 467 } 468 } 469 class question_state_mangrright extends question_state_manuallygraded { 470 public function is_correct() { 471 return true; 472 } 473 public function get_feedback_class() { 474 return 'correct'; 475 } 476 } 477 /**#@-*/ 478 question_state::init();
title
Description
Body
title
Description
Body
title
Description
Body
title
Body