From cefbf74d02e34ad12bf504e538e910ccb3d964df Mon Sep 17 00:00:00 2001 From: Tim Hunt Date: Wed, 7 Dec 2022 23:02:31 +0000 Subject: [PATCH] MDL-74923 quiz: move mod_quiz_display_options to classes folder --- mod/quiz/accessmanager.php | 3 +- mod/quiz/attemptlib.php | 25 ++--- .../backup/moodle2/restore_quiz_stepslib.php | 56 +++++------ mod/quiz/classes/admin_review_setting.php | 8 +- mod/quiz/classes/external.php | 4 +- mod/quiz/classes/question/display_options.php | 91 ++++++++++++++++++ ...otify_attempt_manual_grading_completed.php | 4 +- mod/quiz/db/install.xml | 2 +- mod/quiz/db/renamedclasses.php | 2 + mod/quiz/lib.php | 21 ++-- mod/quiz/locallib.php | 95 +++---------------- mod/quiz/mod_form.php | 17 ++-- mod/quiz/renderer.php | 20 ++-- mod/quiz/report/reportlib.php | 8 +- mod/quiz/tests/external/external_test.php | 6 +- mod/quiz/tests/locallib_test.php | 37 ++++---- .../tests/question/display_options_test.php | 82 ++++++++++++++++ mod/quiz/tests/quizdisplayoptions_test.php | 83 ---------------- mod/quiz/tests/quizobj_test.php | 12 +-- mod/quiz/upgrade.txt | 9 ++ 20 files changed, 313 insertions(+), 272 deletions(-) create mode 100644 mod/quiz/classes/question/display_options.php create mode 100644 mod/quiz/tests/question/display_options_test.php delete mode 100644 mod/quiz/tests/quizdisplayoptions_test.php diff --git a/mod/quiz/accessmanager.php b/mod/quiz/accessmanager.php index c225a6b75e7..f1db4ba549b 100644 --- a/mod/quiz/accessmanager.php +++ b/mod/quiz/accessmanager.php @@ -25,6 +25,7 @@ defined('MOODLE_INTERNAL') || die(); +use mod_quiz\question\display_options; /** * This class keeps track of the various access rules that apply to a particular @@ -528,7 +529,7 @@ class quiz_access_manager { } $when = quiz_attempt_state($this->quizobj->get_quiz(), $attempt); - $reviewoptions = mod_quiz_display_options::make_from_quiz( + $reviewoptions = display_options::make_from_quiz( $this->quizobj->get_quiz(), $when); if (!$reviewoptions->attempt) { diff --git a/mod/quiz/attemptlib.php b/mod/quiz/attemptlib.php index c2b1aab7472..06c1a02c9d2 100644 --- a/mod/quiz/attemptlib.php +++ b/mod/quiz/attemptlib.php @@ -28,6 +28,7 @@ defined('MOODLE_INTERNAL') || die(); use mod_quiz\question\bank\qbank_helper; +use mod_quiz\question\display_options; /** @@ -476,7 +477,7 @@ class quiz { * If $reviewoptions->attempt is false, meaning that students can't review this * attempt at the moment, return an appropriate string explaining why. * - * @param int $when One of the mod_quiz_display_options::DURING, + * @param int $when One of the display_options::DURING, * IMMEDIATELY_AFTER, LATER_WHILE_OPEN or AFTER_CLOSE constants. * @param bool $short if true, return a shorter string. * @return string an appropraite message. @@ -491,11 +492,11 @@ class quiz { $dateformat = ''; } - if ($when == mod_quiz_display_options::DURING || - $when == mod_quiz_display_options::IMMEDIATELY_AFTER) { + if ($when == display_options::DURING || + $when == display_options::IMMEDIATELY_AFTER) { return ''; - } else if ($when == mod_quiz_display_options::LATER_WHILE_OPEN && $this->quiz->timeclose && - $this->quiz->reviewattempt & mod_quiz_display_options::AFTER_CLOSE) { + } else if ($when == display_options::LATER_WHILE_OPEN && $this->quiz->timeclose && + $this->quiz->reviewattempt & display_options::AFTER_CLOSE) { return get_string('noreviewuntil' . $langstrsuffix, 'quiz', userdate($this->quiz->timeclose, $dateformat)); } else { @@ -631,7 +632,7 @@ class quiz_attempt { /** @var array slot => page number for this slot. */ protected $questionpages; - /** @var mod_quiz_display_options cache for the appropriate review options. */ + /** @var display_options cache for the appropriate review options. */ protected $reviewoptions = null; // Constructor ============================================================= @@ -1080,7 +1081,7 @@ class quiz_attempt { * If not, prints an error. */ public function check_review_capability() { - if ($this->get_attempt_state() == mod_quiz_display_options::IMMEDIATELY_AFTER) { + if ($this->get_attempt_state() == display_options::IMMEDIATELY_AFTER) { $capability = 'mod/quiz:attempt'; } else { $capability = 'mod/quiz:reviewmyattempts'; @@ -1132,7 +1133,7 @@ class quiz_attempt { } /** - * @return int one of the mod_quiz_display_options::DURING, + * @return int one of the display_options::DURING, * IMMEDIATELY_AFTER, LATER_WHILE_OPEN or AFTER_CLOSE constants. */ public function get_attempt_state() { @@ -1140,7 +1141,7 @@ class quiz_attempt { } /** - * Wrapper that the correct mod_quiz_display_options for this quiz at the + * Wrapper that the correct display_options for this quiz at the * moment. * * @param bool $reviewing true for options when reviewing, false for when attempting. @@ -1160,15 +1161,15 @@ class quiz_attempt { return $this->reviewoptions; } else { - $options = mod_quiz_display_options::make_from_quiz($this->get_quiz(), - mod_quiz_display_options::DURING); + $options = display_options::make_from_quiz($this->get_quiz(), + display_options::DURING); $options->flags = quiz_get_flag_option($this->attempt, $this->quizobj->get_context()); return $options; } } /** - * Wrapper that the correct mod_quiz_display_options for this quiz at the + * Wrapper that the correct display_options for this quiz at the * moment. * * @param bool $reviewing true for review page, else attempt page. diff --git a/mod/quiz/backup/moodle2/restore_quiz_stepslib.php b/mod/quiz/backup/moodle2/restore_quiz_stepslib.php index 1638e97fab5..62bdee3e621 100644 --- a/mod/quiz/backup/moodle2/restore_quiz_stepslib.php +++ b/mod/quiz/backup/moodle2/restore_quiz_stepslib.php @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Moodle. If not, see . +use mod_quiz\question\display_options; + /** * Structure step to restore one quiz activity * @@ -162,70 +164,70 @@ class restore_quiz_activity_structure_step extends restore_questions_activity_st $oldreview = $data->review; $data->reviewattempt = - mod_quiz_display_options::DURING | + display_options::DURING | ($oldreview & QUIZ_OLD_IMMEDIATELY & QUIZ_OLD_RESPONSES ? - mod_quiz_display_options::IMMEDIATELY_AFTER : 0) | + display_options::IMMEDIATELY_AFTER : 0) | ($oldreview & QUIZ_OLD_OPEN & QUIZ_OLD_RESPONSES ? - mod_quiz_display_options::LATER_WHILE_OPEN : 0) | + display_options::LATER_WHILE_OPEN : 0) | ($oldreview & QUIZ_OLD_CLOSED & QUIZ_OLD_RESPONSES ? - mod_quiz_display_options::AFTER_CLOSE : 0); + display_options::AFTER_CLOSE : 0); $data->reviewcorrectness = - mod_quiz_display_options::DURING | + display_options::DURING | ($oldreview & QUIZ_OLD_IMMEDIATELY & QUIZ_OLD_SCORES ? - mod_quiz_display_options::IMMEDIATELY_AFTER : 0) | + display_options::IMMEDIATELY_AFTER : 0) | ($oldreview & QUIZ_OLD_OPEN & QUIZ_OLD_SCORES ? - mod_quiz_display_options::LATER_WHILE_OPEN : 0) | + display_options::LATER_WHILE_OPEN : 0) | ($oldreview & QUIZ_OLD_CLOSED & QUIZ_OLD_SCORES ? - mod_quiz_display_options::AFTER_CLOSE : 0); + display_options::AFTER_CLOSE : 0); $data->reviewmarks = - mod_quiz_display_options::DURING | + display_options::DURING | ($oldreview & QUIZ_OLD_IMMEDIATELY & QUIZ_OLD_SCORES ? - mod_quiz_display_options::IMMEDIATELY_AFTER : 0) | + display_options::IMMEDIATELY_AFTER : 0) | ($oldreview & QUIZ_OLD_OPEN & QUIZ_OLD_SCORES ? - mod_quiz_display_options::LATER_WHILE_OPEN : 0) | + display_options::LATER_WHILE_OPEN : 0) | ($oldreview & QUIZ_OLD_CLOSED & QUIZ_OLD_SCORES ? - mod_quiz_display_options::AFTER_CLOSE : 0); + display_options::AFTER_CLOSE : 0); $data->reviewspecificfeedback = ($oldreview & QUIZ_OLD_IMMEDIATELY & QUIZ_OLD_FEEDBACK ? - mod_quiz_display_options::DURING : 0) | + display_options::DURING : 0) | ($oldreview & QUIZ_OLD_IMMEDIATELY & QUIZ_OLD_FEEDBACK ? - mod_quiz_display_options::IMMEDIATELY_AFTER : 0) | + display_options::IMMEDIATELY_AFTER : 0) | ($oldreview & QUIZ_OLD_OPEN & QUIZ_OLD_FEEDBACK ? - mod_quiz_display_options::LATER_WHILE_OPEN : 0) | + display_options::LATER_WHILE_OPEN : 0) | ($oldreview & QUIZ_OLD_CLOSED & QUIZ_OLD_FEEDBACK ? - mod_quiz_display_options::AFTER_CLOSE : 0); + display_options::AFTER_CLOSE : 0); $data->reviewgeneralfeedback = ($oldreview & QUIZ_OLD_IMMEDIATELY & QUIZ_OLD_GENERALFEEDBACK ? - mod_quiz_display_options::DURING : 0) | + display_options::DURING : 0) | ($oldreview & QUIZ_OLD_IMMEDIATELY & QUIZ_OLD_GENERALFEEDBACK ? - mod_quiz_display_options::IMMEDIATELY_AFTER : 0) | + display_options::IMMEDIATELY_AFTER : 0) | ($oldreview & QUIZ_OLD_OPEN & QUIZ_OLD_GENERALFEEDBACK ? - mod_quiz_display_options::LATER_WHILE_OPEN : 0) | + display_options::LATER_WHILE_OPEN : 0) | ($oldreview & QUIZ_OLD_CLOSED & QUIZ_OLD_GENERALFEEDBACK ? - mod_quiz_display_options::AFTER_CLOSE : 0); + display_options::AFTER_CLOSE : 0); $data->reviewrightanswer = ($oldreview & QUIZ_OLD_IMMEDIATELY & QUIZ_OLD_ANSWERS ? - mod_quiz_display_options::DURING : 0) | + display_options::DURING : 0) | ($oldreview & QUIZ_OLD_IMMEDIATELY & QUIZ_OLD_ANSWERS ? - mod_quiz_display_options::IMMEDIATELY_AFTER : 0) | + display_options::IMMEDIATELY_AFTER : 0) | ($oldreview & QUIZ_OLD_OPEN & QUIZ_OLD_ANSWERS ? - mod_quiz_display_options::LATER_WHILE_OPEN : 0) | + display_options::LATER_WHILE_OPEN : 0) | ($oldreview & QUIZ_OLD_CLOSED & QUIZ_OLD_ANSWERS ? - mod_quiz_display_options::AFTER_CLOSE : 0); + display_options::AFTER_CLOSE : 0); $data->reviewoverallfeedback = 0 | ($oldreview & QUIZ_OLD_IMMEDIATELY & QUIZ_OLD_OVERALLFEEDBACK ? - mod_quiz_display_options::IMMEDIATELY_AFTER : 0) | + display_options::IMMEDIATELY_AFTER : 0) | ($oldreview & QUIZ_OLD_OPEN & QUIZ_OLD_OVERALLFEEDBACK ? - mod_quiz_display_options::LATER_WHILE_OPEN : 0) | + display_options::LATER_WHILE_OPEN : 0) | ($oldreview & QUIZ_OLD_CLOSED & QUIZ_OLD_OVERALLFEEDBACK ? - mod_quiz_display_options::AFTER_CLOSE : 0); + display_options::AFTER_CLOSE : 0); } // The old popup column from from <= 2.1 need to be mapped to diff --git a/mod/quiz/classes/admin_review_setting.php b/mod/quiz/classes/admin_review_setting.php index ba0e1068252..74fb458843b 100644 --- a/mod/quiz/classes/admin_review_setting.php +++ b/mod/quiz/classes/admin_review_setting.php @@ -35,25 +35,25 @@ defined('MOODLE_INTERNAL') || die(); class mod_quiz_admin_review_setting extends admin_setting { /** * @var integer should match the constants defined in - * {@link mod_quiz_display_options}. Copied for performance reasons. + * {@see display_options}. Copied for performance reasons. */ const DURING = 0x10000; /** * @var integer should match the constants defined in - * {@link mod_quiz_display_options}. Copied for performance reasons. + * {@see display_options}. Copied for performance reasons. */ const IMMEDIATELY_AFTER = 0x01000; /** * @var integer should match the constants defined in - * {@link mod_quiz_display_options}. Copied for performance reasons. + * {@see display_options}. Copied for performance reasons. */ const LATER_WHILE_OPEN = 0x00100; /** * @var integer should match the constants defined in - * {@link mod_quiz_display_options}. Copied for performance reasons. + * {@see display_options}. Copied for performance reasons. */ const AFTER_CLOSE = 0x00010; diff --git a/mod/quiz/classes/external.php b/mod/quiz/classes/external.php index 2520e91fe59..56786ed5dd3 100644 --- a/mod/quiz/classes/external.php +++ b/mod/quiz/classes/external.php @@ -194,8 +194,8 @@ class mod_quiz_external extends external_api { (-1 means use decimalpoints.)', VALUE_OPTIONAL), 'reviewattempt' => new external_value(PARAM_INT, 'Whether users are allowed to review their quiz attempts at various times. This is a bit field, decoded by the - mod_quiz_display_options class. It is formed by ORing together - the constants defined there.', VALUE_OPTIONAL), + \mod_quiz\question\display_options class. It is formed by ORing + together the constants defined there.', VALUE_OPTIONAL), 'reviewcorrectness' => new external_value(PARAM_INT, 'Whether users are allowed to review their quiz attempts at various times. A bit field, like reviewattempt.', VALUE_OPTIONAL), diff --git a/mod/quiz/classes/question/display_options.php b/mod/quiz/classes/question/display_options.php new file mode 100644 index 00000000000..dd980194aab --- /dev/null +++ b/mod/quiz/classes/question/display_options.php @@ -0,0 +1,91 @@ +. + +namespace mod_quiz\question; + +defined('MOODLE_INTERNAL') || die(); +require_once($CFG->dirroot . '/question/engine/lib.php'); + +/** + * An extension of question_display_options that includes the extra options used + * by the quiz. + * + * @copyright 2022 The Open University + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class display_options extends \question_display_options { + /**#@+ + * @var integer bits used to indicate various times in relation to a + * quiz attempt. + */ + const DURING = 0x10000; + const IMMEDIATELY_AFTER = 0x01000; + const LATER_WHILE_OPEN = 0x00100; + const AFTER_CLOSE = 0x00010; + /**#@-*/ + + /** + * @var boolean if this is false, then the student is not allowed to review + * anything about the attempt. + */ + public $attempt = true; + + /** + * @var boolean if this is false, then the student is not allowed to review + * anything about the attempt. + */ + public $overallfeedback = self::VISIBLE; + + /** + * Set up the various options from the quiz settings, and a time constant. + * @param object $quiz the quiz settings. + * @param int $one of the {@link DURING}, {@link IMMEDIATELY_AFTER}, + * {@link LATER_WHILE_OPEN} or {@link AFTER_CLOSE} constants. + * @return display_options set up appropriately. + */ + public static function make_from_quiz($quiz, $when) { + $options = new self(); + + $options->attempt = self::extract($quiz->reviewattempt, $when, true, false); + $options->correctness = self::extract($quiz->reviewcorrectness, $when); + $options->marks = self::extract($quiz->reviewmarks, $when, + self::MARK_AND_MAX, self::MAX_ONLY); + $options->feedback = self::extract($quiz->reviewspecificfeedback, $when); + $options->generalfeedback = self::extract($quiz->reviewgeneralfeedback, $when); + $options->rightanswer = self::extract($quiz->reviewrightanswer, $when); + $options->overallfeedback = self::extract($quiz->reviewoverallfeedback, $when); + + $options->numpartscorrect = $options->feedback; + $options->manualcomment = $options->feedback; + + if ($quiz->questiondecimalpoints != -1) { + $options->markdp = $quiz->questiondecimalpoints; + } else { + $options->markdp = $quiz->decimalpoints; + } + + return $options; + } + + protected static function extract($bitmask, $bit, + $whenset = self::VISIBLE, $whennotset = self::HIDDEN) { + if ($bitmask & $bit) { + return $whenset; + } else { + return $whennotset; + } + } +} diff --git a/mod/quiz/classes/task/quiz_notify_attempt_manual_grading_completed.php b/mod/quiz/classes/task/quiz_notify_attempt_manual_grading_completed.php index 3fd30afcd57..445cdd102b9 100644 --- a/mod/quiz/classes/task/quiz_notify_attempt_manual_grading_completed.php +++ b/mod/quiz/classes/task/quiz_notify_attempt_manual_grading_completed.php @@ -22,7 +22,7 @@ use context_course; use core_user; use moodle_recordset; use question_display_options; -use mod_quiz_display_options; +use mod_quiz\question\display_options; use quiz_attempt; require_once($CFG->dirroot . '/mod/quiz/locallib.php'); @@ -103,7 +103,7 @@ class quiz_notify_attempt_manual_grading_completed extends \core\task\scheduled_ $quiz = quiz_update_effective_access($quiz, $attempt->userid); $attemptobj = new quiz_attempt($attempt, $quiz, $cm, $course, false); - $options = mod_quiz_display_options::make_from_quiz($quiz, quiz_attempt_state($quiz, $attempt)); + $options = display_options::make_from_quiz($quiz, quiz_attempt_state($quiz, $attempt)); if ($options->manualcomment == question_display_options::HIDDEN) { // User cannot currently see the feedback, so don't message them. diff --git a/mod/quiz/db/install.xml b/mod/quiz/db/install.xml index 1031118c67a..6645818404d 100644 --- a/mod/quiz/db/install.xml +++ b/mod/quiz/db/install.xml @@ -23,7 +23,7 @@ - + diff --git a/mod/quiz/db/renamedclasses.php b/mod/quiz/db/renamedclasses.php index 116f788c98f..0ec43824ed2 100644 --- a/mod/quiz/db/renamedclasses.php +++ b/mod/quiz/db/renamedclasses.php @@ -27,4 +27,6 @@ defined('MOODLE_INTERNAL') || die(); $renamedclasses = [ // Since Moodle 4.1. 'mod_quiz\local\views\secondary' => 'mod_quiz\navigation\views\secondary', + // Since Moodle 4.2. + 'mod_quiz_display_options' => 'mod_quiz\question\display_options', ]; diff --git a/mod/quiz/lib.php b/mod/quiz/lib.php index b8fc686a9fc..5ef2e647931 100644 --- a/mod/quiz/lib.php +++ b/mod/quiz/lib.php @@ -29,6 +29,7 @@ defined('MOODLE_INTERNAL') || die(); use mod_quiz\question\bank\custom_view; +use mod_quiz\question\display_options; use core_question\statistics\questions\all_calculated_for_qubaid_condition; require_once($CFG->dirroot . '/calendar/lib.php'); @@ -759,10 +760,10 @@ function quiz_grade_item_update($quiz, $grades = null) { // 2. If the quiz is set to not show grades at either of those times, // create the grade_item as hidden. // 3. If the quiz is set to show grades, create the grade_item visible. - $openreviewoptions = mod_quiz_display_options::make_from_quiz($quiz, - mod_quiz_display_options::LATER_WHILE_OPEN); - $closedreviewoptions = mod_quiz_display_options::make_from_quiz($quiz, - mod_quiz_display_options::AFTER_CLOSE); + $openreviewoptions = display_options::make_from_quiz($quiz, + display_options::LATER_WHILE_OPEN); + $closedreviewoptions = display_options::make_from_quiz($quiz, + display_options::AFTER_CLOSE); if ($openreviewoptions->marks < question_display_options::MARK_AND_MAX && $closedreviewoptions->marks < question_display_options::MARK_AND_MAX) { $params['hidden'] = 1; @@ -1115,8 +1116,8 @@ function quiz_process_options($quiz) { $quiz->reviewgeneralfeedback = quiz_review_option_form_to_db($quiz, 'generalfeedback'); $quiz->reviewrightanswer = quiz_review_option_form_to_db($quiz, 'rightanswer'); $quiz->reviewoverallfeedback = quiz_review_option_form_to_db($quiz, 'overallfeedback'); - $quiz->reviewattempt |= mod_quiz_display_options::DURING; - $quiz->reviewoverallfeedback &= ~mod_quiz_display_options::DURING; + $quiz->reviewattempt |= display_options::DURING; + $quiz->reviewoverallfeedback &= ~display_options::DURING; // Ensure that disabled checkboxes in completion settings are set to 0. // But only if the completion settinsg are unlocked. @@ -1140,10 +1141,10 @@ function quiz_process_options($quiz) { */ function quiz_review_option_form_to_db($fromform, $field) { static $times = array( - 'during' => mod_quiz_display_options::DURING, - 'immediately' => mod_quiz_display_options::IMMEDIATELY_AFTER, - 'open' => mod_quiz_display_options::LATER_WHILE_OPEN, - 'closed' => mod_quiz_display_options::AFTER_CLOSE, + 'during' => display_options::DURING, + 'immediately' => display_options::IMMEDIATELY_AFTER, + 'open' => display_options::LATER_WHILE_OPEN, + 'closed' => display_options::AFTER_CLOSE, ); $review = 0; diff --git a/mod/quiz/locallib.php b/mod/quiz/locallib.php index 087492ab0fa..054a53a4a14 100644 --- a/mod/quiz/locallib.php +++ b/mod/quiz/locallib.php @@ -40,6 +40,7 @@ require_once($CFG->libdir . '/filelib.php'); require_once($CFG->libdir . '/questionlib.php'); use mod_quiz\question\bank\qbank_helper; +use mod_quiz\question\display_options; /** * @var int We show the countdown timer if there is less than this amount of time left before the @@ -1450,8 +1451,8 @@ function quiz_question_edit_button($cmid, $question, $returnurl, $contentafteric */ function quiz_question_preview_url($quiz, $question, $variant = null) { // Get the appropriate display options. - $displayoptions = mod_quiz_display_options::make_from_quiz($quiz, - mod_quiz_display_options::DURING); + $displayoptions = display_options::make_from_quiz($quiz, + display_options::DURING); $maxmark = null; if (isset($question->maxmark)) { @@ -1500,33 +1501,32 @@ function quiz_get_flag_option($attempt, $context) { * quiz_get_review_options, not in the sense of $attempt->state. * @param object $quiz the quiz settings * @param object $attempt the quiz_attempt database row. - * @return int one of the mod_quiz_display_options::DURING, + * @return int one of the display_options::DURING, * IMMEDIATELY_AFTER, LATER_WHILE_OPEN or AFTER_CLOSE constants. */ function quiz_attempt_state($quiz, $attempt) { if ($attempt->state == quiz_attempt::IN_PROGRESS) { - return mod_quiz_display_options::DURING; + return display_options::DURING; } else if ($quiz->timeclose && time() >= $quiz->timeclose) { - return mod_quiz_display_options::AFTER_CLOSE; + return display_options::AFTER_CLOSE; } else if (time() < $attempt->timefinish + 120) { - return mod_quiz_display_options::IMMEDIATELY_AFTER; + return display_options::IMMEDIATELY_AFTER; } else { - return mod_quiz_display_options::LATER_WHILE_OPEN; + return display_options::LATER_WHILE_OPEN; } } /** - * The the appropraite mod_quiz_display_options object for this attempt at this - * quiz right now. + * The appropriate display_options object for this attempt at this quiz right now. * * @param stdClass $quiz the quiz instance. * @param stdClass $attempt the attempt in question. * @param context $context the quiz context. * - * @return mod_quiz_display_options + * @return display_options */ function quiz_get_review_options($quiz, $attempt, $context) { - $options = mod_quiz_display_options::make_from_quiz($quiz, quiz_attempt_state($quiz, $attempt)); + $options = display_options::make_from_quiz($quiz, quiz_attempt_state($quiz, $attempt)); $options->readonly = true; $options->flags = quiz_get_flag_option($attempt, $context); @@ -1595,7 +1595,7 @@ function quiz_get_combined_reviewoptions($quiz, $attempts) { } foreach ($attempts as $attempt) { - $attemptoptions = mod_quiz_display_options::make_from_quiz($quiz, + $attemptoptions = display_options::make_from_quiz($quiz, quiz_attempt_state($quiz, $attempt)); foreach ($fields as $field) { $someoptions->$field = $someoptions->$field || $attemptoptions->$field; @@ -2066,77 +2066,6 @@ function quiz_get_js_module() { } -/** - * An extension of question_display_options that includes the extra options used - * by the quiz. - * - * @copyright 2010 The Open University - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class mod_quiz_display_options extends question_display_options { - /**#@+ - * @var integer bits used to indicate various times in relation to a - * quiz attempt. - */ - const DURING = 0x10000; - const IMMEDIATELY_AFTER = 0x01000; - const LATER_WHILE_OPEN = 0x00100; - const AFTER_CLOSE = 0x00010; - /**#@-*/ - - /** - * @var boolean if this is false, then the student is not allowed to review - * anything about the attempt. - */ - public $attempt = true; - - /** - * @var boolean if this is false, then the student is not allowed to review - * anything about the attempt. - */ - public $overallfeedback = self::VISIBLE; - - /** - * Set up the various options from the quiz settings, and a time constant. - * @param object $quiz the quiz settings. - * @param int $one of the {@link DURING}, {@link IMMEDIATELY_AFTER}, - * {@link LATER_WHILE_OPEN} or {@link AFTER_CLOSE} constants. - * @return mod_quiz_display_options set up appropriately. - */ - public static function make_from_quiz($quiz, $when) { - $options = new self(); - - $options->attempt = self::extract($quiz->reviewattempt, $when, true, false); - $options->correctness = self::extract($quiz->reviewcorrectness, $when); - $options->marks = self::extract($quiz->reviewmarks, $when, - self::MARK_AND_MAX, self::MAX_ONLY); - $options->feedback = self::extract($quiz->reviewspecificfeedback, $when); - $options->generalfeedback = self::extract($quiz->reviewgeneralfeedback, $when); - $options->rightanswer = self::extract($quiz->reviewrightanswer, $when); - $options->overallfeedback = self::extract($quiz->reviewoverallfeedback, $when); - - $options->numpartscorrect = $options->feedback; - $options->manualcomment = $options->feedback; - - if ($quiz->questiondecimalpoints != -1) { - $options->markdp = $quiz->questiondecimalpoints; - } else { - $options->markdp = $quiz->decimalpoints; - } - - return $options; - } - - protected static function extract($bitmask, $bit, - $whenset = self::VISIBLE, $whennotset = self::HIDDEN) { - if ($bitmask & $bit) { - return $whenset; - } else { - return $whennotset; - } - } -} - /** * A {@link qubaid_condition} for finding all the question usages belonging to * a particular quiz. diff --git a/mod/quiz/mod_form.php b/mod/quiz/mod_form.php index a612bd334ca..772b6ddfd7c 100644 --- a/mod/quiz/mod_form.php +++ b/mod/quiz/mod_form.php @@ -28,6 +28,7 @@ defined('MOODLE_INTERNAL') || die(); require_once($CFG->dirroot . '/course/moodleform_mod.php'); require_once($CFG->dirroot . '/mod/quiz/locallib.php'); +use mod_quiz\question\display_options; /** * Settings form for the quiz module. @@ -204,13 +205,13 @@ class mod_quiz_mod_form extends moodleform_mod { // Review options. $this->add_review_options_group($mform, $quizconfig, 'during', - mod_quiz_display_options::DURING, true); + display_options::DURING, true); $this->add_review_options_group($mform, $quizconfig, 'immediately', - mod_quiz_display_options::IMMEDIATELY_AFTER); + display_options::IMMEDIATELY_AFTER); $this->add_review_options_group($mform, $quizconfig, 'open', - mod_quiz_display_options::LATER_WHILE_OPEN); + display_options::LATER_WHILE_OPEN); $this->add_review_options_group($mform, $quizconfig, 'closed', - mod_quiz_display_options::AFTER_CLOSE); + display_options::AFTER_CLOSE); foreach ($behaviours as $behaviour => $notused) { $unusedoptions = question_engine::get_behaviour_unused_display_options($behaviour); @@ -459,13 +460,13 @@ class mod_quiz_mod_form extends moodleform_mod { } $this->preprocessing_review_settings($toform, 'during', - mod_quiz_display_options::DURING); + display_options::DURING); $this->preprocessing_review_settings($toform, 'immediately', - mod_quiz_display_options::IMMEDIATELY_AFTER); + display_options::IMMEDIATELY_AFTER); $this->preprocessing_review_settings($toform, 'open', - mod_quiz_display_options::LATER_WHILE_OPEN); + display_options::LATER_WHILE_OPEN); $this->preprocessing_review_settings($toform, 'closed', - mod_quiz_display_options::AFTER_CLOSE); + display_options::AFTER_CLOSE); $toform['attemptduring'] = true; $toform['overallfeedbackduring'] = false; diff --git a/mod/quiz/renderer.php b/mod/quiz/renderer.php index 395d3f07e82..0055f5b7343 100644 --- a/mod/quiz/renderer.php +++ b/mod/quiz/renderer.php @@ -25,6 +25,8 @@ defined('MOODLE_INTERNAL') || die(); +use mod_quiz\question\display_options; + /** * The renderer for the quiz module. @@ -41,12 +43,12 @@ class mod_quiz_renderer extends plugin_renderer_base { * @param int $page the current page number * @param bool $showall whether to show entire attempt on one page. * @param bool $lastpage if true the current page is the last page. - * @param mod_quiz_display_options $displayoptions instance of mod_quiz_display_options. + * @param display_options $displayoptions instance of display_options. * @param array $summarydata contains all table data * @return $output containing html data. */ public function review_page(quiz_attempt $attemptobj, $slots, $page, $showall, - $lastpage, mod_quiz_display_options $displayoptions, + $lastpage, display_options $displayoptions, $summarydata) { $output = ''; @@ -67,12 +69,12 @@ class mod_quiz_renderer extends plugin_renderer_base { * @param quiz_attempt $attemptobj an instance of quiz_attempt. * @param int $slot which question to display. * @param int $seq which step of the question attempt to show. null = latest. - * @param mod_quiz_display_options $displayoptions instance of mod_quiz_display_options. + * @param display_options $displayoptions instance of display_options. * @param array $summarydata contains all table data * @return $output containing html data. */ public function review_question_page(quiz_attempt $attemptobj, $slot, $seq, - mod_quiz_display_options $displayoptions, $summarydata) { + display_options $displayoptions, $summarydata) { $output = ''; $output .= $this->header(); @@ -177,10 +179,10 @@ class mod_quiz_renderer extends plugin_renderer_base { * @param array $slots array of intgers relating to questions * @param int $page current page number * @param bool $showall if true shows attempt on single page - * @param mod_quiz_display_options $displayoptions instance of mod_quiz_display_options + * @param display_options $displayoptions instance of display_options */ public function questions(quiz_attempt $attemptobj, $reviewing, $slots, $page, $showall, - mod_quiz_display_options $displayoptions) { + display_options $displayoptions) { $output = ''; foreach ($slots as $slot) { $output .= $attemptobj->render_question($slot, $reviewing, $this, @@ -194,7 +196,7 @@ class mod_quiz_renderer extends plugin_renderer_base { * * @param array $summarydata contain row data for table * @param int $page current page number - * @param mod_quiz_display_options $displayoptions instance of mod_quiz_display_options + * @param display_options $displayoptions instance of display_options * @param $content contains each question * @param quiz_attempt $attemptobj instance of quiz_attempt * @param bool $showall if true display attempt on one page @@ -662,7 +664,7 @@ class mod_quiz_renderer extends plugin_renderer_base { * Create the summary page * * @param quiz_attempt $attemptobj - * @param mod_quiz_display_options $displayoptions + * @param display_options $displayoptions */ public function summary_page($attemptobj, $displayoptions) { $output = ''; @@ -680,7 +682,7 @@ class mod_quiz_renderer extends plugin_renderer_base { * Generates the table of summarydata * * @param quiz_attempt $attemptobj - * @param mod_quiz_display_options $displayoptions + * @param display_options $displayoptions */ public function summary_table($attemptobj, $displayoptions) { // Prepare the summary table header. diff --git a/mod/quiz/report/reportlib.php b/mod/quiz/report/reportlib.php index df2e36bf626..da0e996af74 100644 --- a/mod/quiz/report/reportlib.php +++ b/mod/quiz/report/reportlib.php @@ -30,6 +30,8 @@ require_once($CFG->dirroot . '/mod/quiz/attemptlib.php'); require_once($CFG->libdir . '/filelib.php'); require_once($CFG->dirroot . '/mod/quiz/accessmanager.php'); +use mod_quiz\question\display_options; + /** * Takes an array of objects and constructs a multidimensional array keyed by * the keys it finds on the object. @@ -427,11 +429,11 @@ function quiz_no_questions_message($quiz, $cm, $context) { */ function quiz_report_should_show_grades($quiz, context $context) { if ($quiz->timeclose && time() > $quiz->timeclose) { - $when = mod_quiz_display_options::AFTER_CLOSE; + $when = display_options::AFTER_CLOSE; } else { - $when = mod_quiz_display_options::LATER_WHILE_OPEN; + $when = display_options::LATER_WHILE_OPEN; } - $reviewoptions = mod_quiz_display_options::make_from_quiz($quiz, $when); + $reviewoptions = display_options::make_from_quiz($quiz, $when); return quiz_has_grades($quiz) && ($reviewoptions->marks >= question_display_options::MARK_AND_MAX || diff --git a/mod/quiz/tests/external/external_test.php b/mod/quiz/tests/external/external_test.php index 90dd1d39d47..97cccb0bc81 100644 --- a/mod/quiz/tests/external/external_test.php +++ b/mod/quiz/tests/external/external_test.php @@ -28,7 +28,7 @@ namespace mod_quiz\external; use externallib_advanced_testcase; use mod_quiz_external; -use mod_quiz_display_options; +use mod_quiz\question\display_options; use quiz; use quiz_attempt; @@ -681,7 +681,7 @@ class external_test extends externallib_advanced_testcase { } /** * Test get_combined_review_options. - * This is a basic test, this is already tested in mod_quiz_display_options_testcase. + * This is a basic test, this is already tested in display_options_testcase. */ public function test_get_combined_review_options() { global $DB; @@ -1027,7 +1027,7 @@ class external_test extends externallib_advanced_testcase { list($quiz, $context, $quizobj, $attempt, $attemptobj) = $this->create_quiz_with_questions(true); // Set correctness mask so questions state can be fetched only after finishing the attempt. - $DB->set_field('quiz', 'reviewcorrectness', mod_quiz_display_options::IMMEDIATELY_AFTER, array('id' => $quiz->id)); + $DB->set_field('quiz', 'reviewcorrectness', display_options::IMMEDIATELY_AFTER, array('id' => $quiz->id)); $quizobj = $attemptobj->get_quizobj(); $quizobj->preload_questions(); diff --git a/mod/quiz/tests/locallib_test.php b/mod/quiz/tests/locallib_test.php index ae6f4d1d1fe..a5c1809461a 100644 --- a/mod/quiz/tests/locallib_test.php +++ b/mod/quiz/tests/locallib_test.php @@ -25,7 +25,7 @@ namespace mod_quiz; use quiz_attempt; -use mod_quiz_display_options; +use mod_quiz\question\display_options; defined('MOODLE_INTERNAL') || die(); @@ -60,30 +60,31 @@ class locallib_test extends \advanced_testcase { public function quiz_attempt_state_data_provider() { return [ - [quiz_attempt::IN_PROGRESS, null, null, mod_quiz_display_options::DURING], - [quiz_attempt::FINISHED, -90, null, mod_quiz_display_options::IMMEDIATELY_AFTER], - [quiz_attempt::FINISHED, -7200, null, mod_quiz_display_options::LATER_WHILE_OPEN], - [quiz_attempt::FINISHED, -7200, 3600, mod_quiz_display_options::LATER_WHILE_OPEN], - [quiz_attempt::FINISHED, -30, 30, mod_quiz_display_options::IMMEDIATELY_AFTER], - [quiz_attempt::FINISHED, -90, -30, mod_quiz_display_options::AFTER_CLOSE], - [quiz_attempt::FINISHED, -7200, -3600, mod_quiz_display_options::AFTER_CLOSE], - [quiz_attempt::FINISHED, -90, -3600, mod_quiz_display_options::AFTER_CLOSE], - [quiz_attempt::ABANDONED, -10000000, null, mod_quiz_display_options::LATER_WHILE_OPEN], - [quiz_attempt::ABANDONED, -7200, 3600, mod_quiz_display_options::LATER_WHILE_OPEN], - [quiz_attempt::ABANDONED, -7200, -3600, mod_quiz_display_options::AFTER_CLOSE], + [quiz_attempt::IN_PROGRESS, null, null, display_options::DURING], + [quiz_attempt::FINISHED, -90, null, display_options::IMMEDIATELY_AFTER], + [quiz_attempt::FINISHED, -7200, null, display_options::LATER_WHILE_OPEN], + [quiz_attempt::FINISHED, -7200, 3600, display_options::LATER_WHILE_OPEN], + [quiz_attempt::FINISHED, -30, 30, display_options::IMMEDIATELY_AFTER], + [quiz_attempt::FINISHED, -90, -30, display_options::AFTER_CLOSE], + [quiz_attempt::FINISHED, -7200, -3600, display_options::AFTER_CLOSE], + [quiz_attempt::FINISHED, -90, -3600, display_options::AFTER_CLOSE], + [quiz_attempt::ABANDONED, -10000000, null, display_options::LATER_WHILE_OPEN], + [quiz_attempt::ABANDONED, -7200, 3600, display_options::LATER_WHILE_OPEN], + [quiz_attempt::ABANDONED, -7200, -3600, display_options::AFTER_CLOSE], ]; } /** * @dataProvider quiz_attempt_state_data_provider * - * @param unknown $attemptstate as in the quiz_attempts.state DB column. - * @param unknown $relativetimefinish time relative to now when the attempt finished, or null for 0. - * @param unknown $relativetimeclose time relative to now when the quiz closes, or null for 0. - * @param unknown $expectedstate expected result. One of the mod_quiz_display_options constants/ + * @param string $attemptstate as in the quiz_attempts.state DB column. + * @param int|null $relativetimefinish time relative to now when the attempt finished, or null for 0. + * @param int|null $relativetimeclose time relative to now when the quiz closes, or null for 0. + * @param int $expectedstate expected result. One of the display_options constants. + * @covers ::quiz_attempt_state */ - public function test_quiz_attempt_state($attemptstate, - $relativetimefinish, $relativetimeclose, $expectedstate) { + public function test_quiz_attempt_state(string $attemptstate, + ?int $relativetimefinish, ?int $relativetimeclose, int $expectedstate) { $attempt = new \stdClass(); $attempt->state = $attemptstate; diff --git a/mod/quiz/tests/question/display_options_test.php b/mod/quiz/tests/question/display_options_test.php new file mode 100644 index 00000000000..135cbb80a63 --- /dev/null +++ b/mod/quiz/tests/question/display_options_test.php @@ -0,0 +1,82 @@ +. + +namespace mod_quiz\question; + +defined('MOODLE_INTERNAL') || die(); + +global $CFG; +require_once($CFG->dirroot . '/mod/quiz/locallib.php'); + +/** + * Unit tests for {@see display_options}. + * + * @package mod_quiz + * @category test + * @copyright 2010 The Open University + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @covers \mod_quiz\question\display_options + */ +class display_options_test extends \basic_testcase { + public function test_num_attempts_access_rule() { + $quiz = new \stdClass(); + $quiz->decimalpoints = 2; + $quiz->questiondecimalpoints = -1; + $quiz->reviewattempt = 0x11110; + $quiz->reviewcorrectness = 0x10000; + $quiz->reviewmarks = 0x01110; + $quiz->reviewspecificfeedback = 0x10000; + $quiz->reviewgeneralfeedback = 0x01000; + $quiz->reviewrightanswer = 0x00100; + $quiz->reviewoverallfeedback = 0x00010; + + $options = display_options::make_from_quiz($quiz, + display_options::DURING); + + $this->assertEquals(true, $options->attempt); + $this->assertEquals(display_options::VISIBLE, $options->correctness); + $this->assertEquals(display_options::MAX_ONLY, $options->marks); + $this->assertEquals(display_options::VISIBLE, $options->feedback); + // The next two should be controlled by the same settings as ->feedback. + $this->assertEquals(display_options::VISIBLE, $options->numpartscorrect); + $this->assertEquals(display_options::VISIBLE, $options->manualcomment); + $this->assertEquals(2, $options->markdp); + + $quiz->questiondecimalpoints = 5; + $options = display_options::make_from_quiz($quiz, + display_options::IMMEDIATELY_AFTER); + + $this->assertEquals(display_options::MARK_AND_MAX, $options->marks); + $this->assertEquals(display_options::VISIBLE, $options->generalfeedback); + $this->assertEquals(display_options::HIDDEN, $options->feedback); + // The next two should be controlled by the same settings as ->feedback. + $this->assertEquals(display_options::HIDDEN, $options->numpartscorrect); + $this->assertEquals(display_options::HIDDEN, $options->manualcomment); + $this->assertEquals(5, $options->markdp); + + $options = display_options::make_from_quiz($quiz, + display_options::LATER_WHILE_OPEN); + + $this->assertEquals(display_options::VISIBLE, $options->rightanswer); + $this->assertEquals(display_options::HIDDEN, $options->generalfeedback); + + $options = display_options::make_from_quiz($quiz, + display_options::AFTER_CLOSE); + + $this->assertEquals(display_options::VISIBLE, $options->overallfeedback); + $this->assertEquals(display_options::HIDDEN, $options->rightanswer); + } +} diff --git a/mod/quiz/tests/quizdisplayoptions_test.php b/mod/quiz/tests/quizdisplayoptions_test.php deleted file mode 100644 index c3714252ba6..00000000000 --- a/mod/quiz/tests/quizdisplayoptions_test.php +++ /dev/null @@ -1,83 +0,0 @@ -. - -namespace mod_quiz; - -use mod_quiz_display_options; - -defined('MOODLE_INTERNAL') || die(); - -global $CFG; -require_once($CFG->dirroot . '/mod/quiz/locallib.php'); - -/** - * Unit tests for {@link mod_quiz_display_options}. - * - * @package mod_quiz - * @category test - * @copyright 2010 The Open University - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class quizdisplayoptions_test extends \basic_testcase { - public function test_num_attempts_access_rule() { - $quiz = new \stdClass(); - $quiz->decimalpoints = 2; - $quiz->questiondecimalpoints = -1; - $quiz->reviewattempt = 0x11110; - $quiz->reviewcorrectness = 0x10000; - $quiz->reviewmarks = 0x01110; - $quiz->reviewspecificfeedback = 0x10000; - $quiz->reviewgeneralfeedback = 0x01000; - $quiz->reviewrightanswer = 0x00100; - $quiz->reviewoverallfeedback = 0x00010; - - $options = mod_quiz_display_options::make_from_quiz($quiz, - mod_quiz_display_options::DURING); - - $this->assertEquals(true, $options->attempt); - $this->assertEquals(mod_quiz_display_options::VISIBLE, $options->correctness); - $this->assertEquals(mod_quiz_display_options::MAX_ONLY, $options->marks); - $this->assertEquals(mod_quiz_display_options::VISIBLE, $options->feedback); - // The next two should be controlled by the same settings as ->feedback. - $this->assertEquals(mod_quiz_display_options::VISIBLE, $options->numpartscorrect); - $this->assertEquals(mod_quiz_display_options::VISIBLE, $options->manualcomment); - $this->assertEquals(2, $options->markdp); - - $quiz->questiondecimalpoints = 5; - $options = mod_quiz_display_options::make_from_quiz($quiz, - mod_quiz_display_options::IMMEDIATELY_AFTER); - - $this->assertEquals(mod_quiz_display_options::MARK_AND_MAX, $options->marks); - $this->assertEquals(mod_quiz_display_options::VISIBLE, $options->generalfeedback); - $this->assertEquals(mod_quiz_display_options::HIDDEN, $options->feedback); - // The next two should be controlled by the same settings as ->feedback. - $this->assertEquals(mod_quiz_display_options::HIDDEN, $options->numpartscorrect); - $this->assertEquals(mod_quiz_display_options::HIDDEN, $options->manualcomment); - $this->assertEquals(5, $options->markdp); - - $options = mod_quiz_display_options::make_from_quiz($quiz, - mod_quiz_display_options::LATER_WHILE_OPEN); - - $this->assertEquals(mod_quiz_display_options::VISIBLE, $options->rightanswer); - $this->assertEquals(mod_quiz_display_options::HIDDEN, $options->generalfeedback); - - $options = mod_quiz_display_options::make_from_quiz($quiz, - mod_quiz_display_options::AFTER_CLOSE); - - $this->assertEquals(mod_quiz_display_options::VISIBLE, $options->overallfeedback); - $this->assertEquals(mod_quiz_display_options::HIDDEN, $options->rightanswer); - } -} diff --git a/mod/quiz/tests/quizobj_test.php b/mod/quiz/tests/quizobj_test.php index fa141b2a4d8..2877b19cf4e 100644 --- a/mod/quiz/tests/quizobj_test.php +++ b/mod/quiz/tests/quizobj_test.php @@ -16,7 +16,7 @@ namespace mod_quiz; -use mod_quiz_display_options; +use mod_quiz\question\display_options; use quiz; defined('MOODLE_INTERNAL') || die(); @@ -44,19 +44,19 @@ class quizobj_test extends \basic_testcase { $quizobj = new quiz($quiz, $cm, new \stdClass(), false); $this->assertEquals('', - $quizobj->cannot_review_message(mod_quiz_display_options::DURING)); + $quizobj->cannot_review_message(display_options::DURING)); $this->assertEquals('', - $quizobj->cannot_review_message(mod_quiz_display_options::IMMEDIATELY_AFTER)); + $quizobj->cannot_review_message(display_options::IMMEDIATELY_AFTER)); $this->assertEquals(get_string('noreview', 'quiz'), - $quizobj->cannot_review_message(mod_quiz_display_options::LATER_WHILE_OPEN)); + $quizobj->cannot_review_message(display_options::LATER_WHILE_OPEN)); $this->assertEquals(get_string('noreview', 'quiz'), - $quizobj->cannot_review_message(mod_quiz_display_options::AFTER_CLOSE)); + $quizobj->cannot_review_message(display_options::AFTER_CLOSE)); $closetime = time() + 10000; $quiz->timeclose = $closetime; $quizobj = new quiz($quiz, $cm, new \stdClass(), false); $this->assertEquals(get_string('noreviewuntil', 'quiz', userdate($closetime)), - $quizobj->cannot_review_message(mod_quiz_display_options::LATER_WHILE_OPEN)); + $quizobj->cannot_review_message(display_options::LATER_WHILE_OPEN)); } } diff --git a/mod/quiz/upgrade.txt b/mod/quiz/upgrade.txt index c412c99f6fa..209b5881af9 100644 --- a/mod/quiz/upgrade.txt +++ b/mod/quiz/upgrade.txt @@ -1,5 +1,14 @@ This files describes API changes in the quiz code. +=== 4.2 === + +* The quiz has a lot of old classes in lib.php files. These have now been moved into the classes folder, + and so are now in namespaces. Because of Moodle's class renaming support, your code should continue + working, but output deprecated warnings, so you probably want to update. This should mostly be + doable by adding use statements, and a search/replace. + - mod_quiz_display_options => mod_quiz\question\display_options + + === 4.1 === * quiz_has_question_use is now deprecated. Use mod_quiz\structure::has_use_capability istead.