See Release Notes
Long Term Support Release
<?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * This defines the states a question can be in. * * @package moodlecore * @subpackage questionengine * @copyright 2010 The Open University * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); /** * An enumeration representing the states a question can be in after a * {@link question_attempt_step}. * * There are also some useful methods for testing and manipulating states. * * @copyright 2009 The Open University * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ abstract class question_state { /**#@+ * Specific question_state instances. */ public static $notstarted; public static $unprocessed; public static $todo; public static $invalid; public static $complete; public static $needsgrading; public static $finished; public static $gaveup; public static $gradedwrong; public static $gradedpartial; public static $gradedright; public static $manfinished; public static $mangaveup; public static $mangrwrong; public static $mangrpartial; public static $mangrright; /**#@+-*/ protected function __construct() { } public static function init() { $us = new ReflectionClass('question_state'); foreach ($us->getStaticProperties() as $name => $notused) { $class = 'question_state_' . $name; $states[$name] = new $class(); self::$$name = $states[$name]; } } /** * Get all the states in an array. * * @return question_state[] of question_state objects. */ public static function get_all() { $states = array(); $us = new ReflectionClass('question_state'); foreach ($us->getStaticProperties() as $name => $notused) { $states[] = self::$$name; } return $states; } /** * Get all the states in an array. * @param string $summarystate one of the four summary states * inprogress, needsgrading, manuallygraded or autograded. * @return array of the corresponding states. */ public static function get_all_for_summary_state($summarystate) { $states = array(); foreach (self::get_all() as $state) { if ($state->get_summary_state() == $summarystate) { $states[] = $state; } } if (empty($states)) { throw new coding_exception('unknown summary state ' . $summarystate); } return $states; } /** * @return string convert this state to a string. */ public function __toString() { return substr(get_class($this), 15); } /**> * Get the instance of this class for a given state name. * @param string $name a state name. > *< * @return question_state the state with that name.> * @return question_state|null the state with that name. (Null only in an exceptional case.)*/< public static function get($name) {> public static function get(string $name): ?question_state { > // In the past, there was a bug where null states got stored > // in the database as an empty string, which was wrong because > // the state column should be NOT NULL. > // That is no longer possible, but we need to avoid exceptions > // for people with old bad data in their database. > if ($name === '') { > debugging('Attempt to create a state from an empty string. ' . > 'This is probably a sign of bad data in your database. See MDL-80127.'); > return null; > } >return self::$$name; } /** * Is this state one of the ones that mean the question attempt is in progress? * That is, started, but no finished. * @return bool */ public function is_active() { return false; } /** * Is this state one of the ones that mean the question attempt is finished? * That is, no further interaction possible, apart from manual grading. * @return bool */ public function is_finished() { return true; } /** * Is this state one of the ones that mean the question attempt has been graded? * @return bool */ public function is_graded() { return false; } /** * Is this state one of the ones that mean the question attempt has been graded? * @return bool */ public function is_correct() { return false; } /** * Is this state one of the ones that mean the question attempt has been graded? * @return bool */ public function is_partially_correct() { return false; } /** * Is this state one of the ones that mean the question attempt has been graded? * @return bool */ public function is_incorrect() { return false; } /** * Is this state one of the ones that mean the question attempt has been graded? * @return bool */ public function is_gave_up() { return false; } /** * Is this state one of the ones that mean the question attempt has had a manual comment added? * @return bool */ public function is_commented() { return false; } /** * Each state can be categorised into one of four categories: * inprogress, needsgrading, manuallygraded or autograded. * @return string which category this state falls into. */ public function get_summary_state() { if (!$this->is_finished()) { return 'inprogress'; } else if ($this == self::$needsgrading) { return 'needsgrading'; } else if ($this->is_commented()) { return 'manuallygraded'; } else { return 'autograded'; } } /** * Return the appropriate graded state based on a fraction. That is 0 or less * is $graded_incorrect, 1 is $graded_correct, otherwise it is $graded_partcorrect. * Appropriate allowance is made for rounding float values. * * @param number $fraction the grade, on the fraction scale. * @return question_state one of the state constants. */ public static function graded_state_for_fraction($fraction) { if ($fraction < 0.000001) { return self::$gradedwrong; } else if ($fraction > 0.999999) { return self::$gradedright; } else { return self::$gradedpartial; } } /** * Return the appropriate manually graded state based on a fraction. That is 0 or less * is $manually_graded_incorrect, 1 is $manually_graded_correct, otherwise it is * $manually_graded_partcorrect. Appropriate allowance is made for rounding float values. * * @param number $fraction the grade, on the fraction scale. * @return int one of the state constants. */ public static function manually_graded_state_for_fraction($fraction) { if (is_null($fraction)) { return self::$needsgrading; } else if ($fraction < 0.000001) { return self::$mangrwrong; } else if ($fraction > 0.999999) { return self::$mangrright; } else { return self::$mangrpartial; } } /** * Compute an appropriate state to move to after a manual comment has been * added to this state. * @param number $fraction the manual grade (if any) on the fraction scale. * @return int the new state. */ public function corresponding_commented_state($fraction) { throw new coding_exception('Unexpected question state.'); } /** * Return an appropriate CSS class name ''/'correct'/'partiallycorrect'/'incorrect', * for a state. * @return string */ public function get_feedback_class() { return ''; } /** * Return the name of an appropriate string to look up in the question * language pack for a state. This is used, for example, by * {@link question_behaviour::get_state_string()}. However, behaviours * sometimes change this default string for soemthing more specific. * * @param bool $showcorrectness Whether right/partial/wrong states should * be distinguised, or just treated as 'complete'. * @return string the name of a string that can be looked up in the 'question' * lang pack, or used as a CSS class name, etc. */ public abstract function get_state_class($showcorrectness); /** * The result of doing get_string on the result of {@link get_state_class()}. * * @param bool $showcorrectness Whether right/partial/wrong states should * be distinguised. * @return string a string from the lang pack that can be used in the UI. */ public function default_string($showcorrectness) { return get_string($this->get_state_class($showcorrectness), 'question'); } } /**#@+ * Specific question_state subclasses. * * @copyright 2009 The Open University * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class question_state_notstarted extends question_state { public function is_finished() { return false; } public function get_state_class($showcorrectness) { throw new coding_exception('Unexpected question state.'); } } class question_state_unprocessed extends question_state { public function is_finished() { return false; } public function get_state_class($showcorrectness) { throw new coding_exception('Unexpected question state.'); } } class question_state_todo extends question_state { public function is_active() { return true; } public function is_finished() { return false; } public function get_state_class($showcorrectness) { return 'notyetanswered'; } } class question_state_invalid extends question_state { public function is_active() { return true; } public function is_finished() { return false; } public function get_state_class($showcorrectness) { return 'invalidanswer'; } } class question_state_complete extends question_state { public function is_active() { return true; } public function is_finished() { return false; } public function get_state_class($showcorrectness) { return 'answersaved'; } } class question_state_needsgrading extends question_state { public function get_state_class($showcorrectness) { if ($showcorrectness) { return 'requiresgrading'; } else { return 'complete'; } } public function corresponding_commented_state($fraction) { return self::manually_graded_state_for_fraction($fraction); } } class question_state_finished extends question_state { public function get_state_class($showcorrectness) { return 'complete'; } public function corresponding_commented_state($fraction) { return self::$manfinished; } } class question_state_gaveup extends question_state { public function is_gave_up() { return true; } public function get_feedback_class() { return 'incorrect'; } public function get_state_class($showcorrectness) { return 'notanswered'; } public function corresponding_commented_state($fraction) { if (is_null($fraction)) { return self::$mangaveup; } else { return self::manually_graded_state_for_fraction($fraction); } } } abstract class question_state_graded extends question_state { public function is_graded() { return true; } public function get_state_class($showcorrectness) { if ($showcorrectness) { return $this->get_feedback_class(); } else { return 'complete'; } } public function corresponding_commented_state($fraction) { return self::manually_graded_state_for_fraction($fraction); } } class question_state_gradedwrong extends question_state_graded { public function is_incorrect() { return true; } public function get_feedback_class() { return 'incorrect'; } } class question_state_gradedpartial extends question_state_graded { public function is_graded() { return true; } public function is_partially_correct() { return true; } public function get_feedback_class() { return 'partiallycorrect'; } } class question_state_gradedright extends question_state_graded { public function is_graded() { return true; } public function is_correct() { return true; } public function get_feedback_class() { return 'correct'; } } class question_state_manfinished extends question_state_finished { public function is_commented() { return true; } } class question_state_mangaveup extends question_state_gaveup { public function is_commented() { return true; } } abstract class question_state_manuallygraded extends question_state_graded { public function is_commented() { return true; } } class question_state_mangrwrong extends question_state_manuallygraded { public function is_incorrect() { return false; } public function get_feedback_class() { return 'incorrect'; } } class question_state_mangrpartial extends question_state_manuallygraded { public function is_partially_correct() { return true; } public function get_feedback_class() { return 'partiallycorrect'; } } class question_state_mangrright extends question_state_manuallygraded { public function is_correct() { return true; } public function get_feedback_class() { return 'correct'; } } /**#@-*/ question_state::init();