From 334b6c75a43ea2a72995d14ee9526e6b82662270 Mon Sep 17 00:00:00 2001 From: Paul Holden Date: Fri, 5 May 2023 10:32:01 +0100 Subject: [PATCH] MDL-71196 completion: final removal of get_completion_state support. --- completion/classes/cm_completion_details.php | 11 - completion/upgrade.txt | 2 + lib/completionlib.php | 13 - mod/assign/deprecatedlib.php | 34 +-- mod/assign/tests/lib_test.php | 32 -- mod/choice/deprecatedlib.php | 30 +- mod/data/deprecatedlib.php | 38 +-- mod/feedback/deprecatedlib.php | 29 +- mod/forum/deprecatedlib.php | 66 +---- mod/glossary/deprecatedlib.php | 36 +-- mod/lesson/deprecatedlib.php | 48 +-- mod/quiz/deprecatedlib.php | 109 +------ mod/quiz/tests/lib_test.php | 293 ------------------- mod/scorm/deprecatedlib.php | 116 +------- mod/survey/deprecatedlib.php | 29 +- 15 files changed, 32 insertions(+), 854 deletions(-) diff --git a/completion/classes/cm_completion_details.php b/completion/classes/cm_completion_details.php index e80a1182266..b879e35a882 100644 --- a/completion/classes/cm_completion_details.php +++ b/completion/classes/cm_completion_details.php @@ -152,17 +152,6 @@ class cm_completion_details { $details = $this->sort_completion_details($details); } - } else { - if (function_exists($this->cminfo->modname . '_get_completion_state')) { - // If the plugin does not have the custom completion implementation but implements the get_completion_state() callback, - // fallback to displaying the overall completion state of the activity. - $details = [ - 'plugincompletionstate' => (object)[ - 'status' => $this->get_overall_completion(), - 'description' => get_string('completeactivity', 'completion') - ] - ]; - } } return $details; diff --git a/completion/upgrade.txt b/completion/upgrade.txt index ec61f31a76e..9a3782b4b1a 100644 --- a/completion/upgrade.txt +++ b/completion/upgrade.txt @@ -5,6 +5,8 @@ information provided here is intended especially for developers. * A trait class, core_completion/form/form_trait has been added to reuse code for adding and validation completion settings to any form. * New method is_manual() has been added to `core_completion/cm_completion_details` +* Support for deprecated `[modname]_get_completion_state` callbacks has been removed, custom completion rules must be implemented + by appropriate `mod_[modname]\completion\custom_completion` class instead === 4.0 === * New method mark_course_completions_activity_criteria() has been added to mark course completions instantly. It is diff --git a/lib/completionlib.php b/lib/completionlib.php index dafb99c09f2..59fdb3a9dc9 100644 --- a/lib/completionlib.php +++ b/lib/completionlib.php @@ -720,19 +720,6 @@ class completion_info { /** @var activity_custom_completion $cmcompletion */ $cmcompletion = new $cmcompletionclass($cminfo, $userid, $completionstate); $response = $cmcompletion->get_overall_completion_state() != COMPLETION_INCOMPLETE; - } else { - // Fallback to the get_completion_state callback. - $cmcompletionclass = "mod_{$cminfo->modname}\\completion\\custom_completion"; - $function = $cminfo->modname . '_get_completion_state'; - if (!function_exists($function)) { - $this->internal_systemerror("Module {$cminfo->modname} claims to support FEATURE_COMPLETION_HAS_RULES " . - "but does not implement the custom completion class $cmcompletionclass which extends " . - "\core_completion\activity_custom_completion."); - } - debugging("*_get_completion_state() callback functions such as $function have been deprecated and should no " . - "longer be used. Please implement the custom completion class $cmcompletionclass which extends " . - "\core_completion\activity_custom_completion.", DEBUG_DEVELOPER); - $response = $function($this->course, $cm, $userid, COMPLETION_AND, $completionstate); } if (!$response) { diff --git a/mod/assign/deprecatedlib.php b/mod/assign/deprecatedlib.php index 87b3ad2a76b..5b41d9858ed 100644 --- a/mod/assign/deprecatedlib.php +++ b/mod/assign/deprecatedlib.php @@ -23,39 +23,11 @@ */ /** - * Obtains the automatic completion state for this module based on any conditions - * in assign settings. - * * @deprecated since Moodle 3.11 - * @todo MDL-71196 Final deprecation in Moodle 4.3 - * @see \mod_assign\completion\custom_completion - * @param object $course Course - * @param object $cm Course-module - * @param int $userid User ID - * @param bool $type Type of comparison (or/and; can be used as return value if no conditions) - * @return bool True if completed, false if not, $type if conditions not set. */ -function assign_get_completion_state($course, $cm, $userid, $type) { - global $CFG; - - // No need to call debugging here. Deprecation debugging notice already being called in \completion_info::internal_get_state(). - - require_once($CFG->dirroot . '/mod/assign/locallib.php'); - - $assign = new assign(null, $cm, $course); - - // If completion option is enabled, evaluate it and return true/false. - if ($assign->get_instance()->completionsubmit) { - if ($assign->get_instance()->teamsubmission) { - $submission = $assign->get_group_submission($userid, 0, false); - } else { - $submission = $assign->get_user_submission($userid, false); - } - return $submission && $submission->status == ASSIGN_SUBMISSION_STATUS_SUBMITTED; - } else { - // Completion option is not enabled so just return $type. - return $type; - } +function assign_get_completion_state() { + $completionclass = \mod_assign\completion\custom_completion::class; + throw new coding_exception(__FUNCTION__ . "() has been removed, please use the '{$completionclass}' class instead"); } /** diff --git a/mod/assign/tests/lib_test.php b/mod/assign/tests/lib_test.php index 5fad64323d4..7fcba8c57d4 100644 --- a/mod/assign/tests/lib_test.php +++ b/mod/assign/tests/lib_test.php @@ -176,38 +176,6 @@ class lib_test extends \advanced_testcase { $this->assertMatchesRegularExpression('/50.5/', $result->info); } - /** - * Ensure that assign_get_completion_state reflects the correct status at each point. - */ - public function test_assign_get_completion_state() { - global $DB; - - $this->resetAfterTest(); - $course = $this->getDataGenerator()->create_course(); - $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher'); - $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); - $assign = $this->create_instance($course, [ - 'submissiondrafts' => 0, - 'completionsubmit' => 1 - ]); - - $this->setUser($student); - $result = assign_get_completion_state($course, $assign->get_course_module(), $student->id, false); - $this->assertFalse($result); - - $this->add_submission($student, $assign); - $result = assign_get_completion_state($course, $assign->get_course_module(), $student->id, false); - $this->assertFalse($result); - - $this->submit_for_grading($student, $assign); - $result = assign_get_completion_state($course, $assign->get_course_module(), $student->id, false); - $this->assertTrue($result); - - $this->mark_submission($teacher, $assign, $student, 50.0); - $result = assign_get_completion_state($course, $assign->get_course_module(), $student->id, false); - $this->assertTrue($result); - } - /** * Tests for mod_assign_refresh_events. */ diff --git a/mod/choice/deprecatedlib.php b/mod/choice/deprecatedlib.php index 80f9b5078ff..6a9613c520d 100644 --- a/mod/choice/deprecatedlib.php +++ b/mod/choice/deprecatedlib.php @@ -23,33 +23,9 @@ */ /** - * Obtains the automatic completion state for this choice based on any conditions - * in forum settings. - * * @deprecated since Moodle 3.11 - * @todo MDL-71196 Final deprecation in Moodle 4.3 - * @see \mod_choice\completion\custom_completion - * @param object $course Course - * @param object $cm Course-module - * @param int $userid User ID - * @param bool $type Type of comparison (or/and; can be used as return value if no conditions) - * @return bool True if completed, false if not, $type if conditions not set. */ -function choice_get_completion_state($course, $cm, $userid, $type) { - global $DB; - - // No need to call debugging here. Deprecation debugging notice already being called in \completion_info::internal_get_state(). - - // Get choice details. - $choice = $DB->get_record('choice', array('id' => $cm->instance), '*', - MUST_EXIST); - - // If completion option is enabled, evaluate it and return true/false. - if ($choice->completionsubmit) { - return $DB->record_exists('choice_answers', array( - 'choiceid' => $choice->id, 'userid' => $userid)); - } else { - // Completion option is not enabled so just return $type. - return $type; - } +function choice_get_completion_state() { + $completionclass = \mod_choice\completion\custom_completion::class; + throw new coding_exception(__FUNCTION__ . "() has been removed, please use the '{$completionclass}' class instead"); } diff --git a/mod/data/deprecatedlib.php b/mod/data/deprecatedlib.php index 5362dca9c12..4f43763bafb 100644 --- a/mod/data/deprecatedlib.php +++ b/mod/data/deprecatedlib.php @@ -23,43 +23,11 @@ */ /** - * Obtains the automatic completion state for this database item based on any conditions - * on its settings. The call for this is in completion lib where the modulename is appended - * to the function name. This is why there are unused parameters. - * * @deprecated since Moodle 3.11 - * @todo MDL-71196 Final deprecation in Moodle 4.3 - * @see \mod_data\completion\custom_completion - * @since Moodle 3.3 - * @param stdClass $course Course - * @param cm_info|stdClass $cm course-module - * @param int $userid User ID - * @param bool $type Type of comparison (or/and; can be used as return value if no conditions) - * @return bool True if completed, false if not, $type if conditions not set. */ -function data_get_completion_state($course, $cm, $userid, $type) { - global $DB, $PAGE; - - // No need to call debugging here. Deprecation debugging notice already being called in \completion_info::internal_get_state(). - - $result = $type; // Default return value - // Get data details. - if (isset($PAGE->cm->id) && $PAGE->cm->id == $cm->id) { - $data = $PAGE->activityrecord; - } else { - $data = $DB->get_record('data', array('id' => $cm->instance), '*', MUST_EXIST); - } - // If completion option is enabled, evaluate it and return true/false. - if ($data->completionentries) { - $numentries = data_numentries($data, $userid); - // Check the number of entries required against the number of entries already made. - if ($numentries >= $data->completionentries) { - $result = true; - } else { - $result = false; - } - } - return $result; +function data_get_completion_state() { + $completionclass = \mod_data\completion\custom_completion::class; + throw new coding_exception(__FUNCTION__ . "() has been removed, please use the '{$completionclass}' class instead"); } /** diff --git a/mod/feedback/deprecatedlib.php b/mod/feedback/deprecatedlib.php index e22022f78b4..62a15564b83 100644 --- a/mod/feedback/deprecatedlib.php +++ b/mod/feedback/deprecatedlib.php @@ -23,32 +23,9 @@ */ /** - * Obtains the automatic completion state for this feedback based on the condition - * in feedback settings. - * * @deprecated since Moodle 3.11 - * @todo MDL-71196 Final deprecation in Moodle 4.3 - * @see \mod_feedback\completion\custom_completion - * @param object $course Course - * @param object $cm Course-module - * @param int $userid User ID - * @param bool $type Type of comparison (or/and; can be used as return value if no conditions) - * @return bool True if completed, false if not, $type if conditions not set. */ -function feedback_get_completion_state($course, $cm, $userid, $type) { - global $DB; - - // No need to call debugging here. Deprecation debugging notice already being called in \completion_info::internal_get_state(). - - // Get feedback details. - $feedback = $DB->get_record('feedback', array('id' => $cm->instance), '*', MUST_EXIST); - - // If completion option is enabled, evaluate it and return true/false. - if ($feedback->completionsubmit) { - $params = array('userid' => $userid, 'feedback' => $feedback->id); - return $DB->record_exists('feedback_completed', $params); - } else { - // Completion option is not enabled so just return $type. - return $type; - } +function feedback_get_completion_state() { + $completionclass = \mod_feedback\completion\custom_completion::class; + throw new coding_exception(__FUNCTION__ . "() has been removed, please use the '{$completionclass}' class instead"); } diff --git a/mod/forum/deprecatedlib.php b/mod/forum/deprecatedlib.php index 5a170345129..d07a1675f36 100644 --- a/mod/forum/deprecatedlib.php +++ b/mod/forum/deprecatedlib.php @@ -410,71 +410,11 @@ function forum_get_user_grades() { } /** - * Obtains the automatic completion state for this forum based on any conditions - * in forum settings. - * * @deprecated since Moodle 3.11 - * @todo MDL-71196 Final deprecation in Moodle 4.3 - * @see \mod_forum\completion\custom_completion - * @global object - * @global object - * @param object $course Course - * @param object $cm Course-module - * @param int $userid User ID - * @param bool $type Type of comparison (or/and; can be used as return value if no conditions) - * @return bool True if completed, false if not. (If no conditions, then return - * value depends on comparison type) */ -function forum_get_completion_state($course, $cm, $userid, $type) { - global $DB; - - // No need to call debugging here. Deprecation debugging notice already being called in \completion_info::internal_get_state(). - - // Get forum details. - if (!($forum = $DB->get_record('forum', array('id' => $cm->instance)))) { - throw new Exception("Can't find forum {$cm->instance}"); - } - - $result = $type; // Default return value. - - $postcountparams = array('userid' => $userid, 'forumid' => $forum->id); - $postcountsql = " -SELECT - COUNT(1) -FROM - {forum_posts} fp - INNER JOIN {forum_discussions} fd ON fp.discussion=fd.id -WHERE - fp.userid=:userid AND fd.forum=:forumid"; - - if ($forum->completiondiscussions) { - $value = $forum->completiondiscussions <= - $DB->count_records('forum_discussions', array('forum' => $forum->id, 'userid' => $userid)); - if ($type == COMPLETION_AND) { - $result = $result && $value; - } else { - $result = $result || $value; - } - } - if ($forum->completionreplies) { - $value = $forum->completionreplies <= - $DB->get_field_sql($postcountsql . ' AND fp.parent<>0', $postcountparams); - if ($type == COMPLETION_AND) { - $result = $result && $value; - } else { - $result = $result || $value; - } - } - if ($forum->completionposts) { - $value = $forum->completionposts <= $DB->get_field_sql($postcountsql, $postcountparams); - if ($type == COMPLETION_AND) { - $result = $result && $value; - } else { - $result = $result || $value; - } - } - - return $result; +function forum_get_completion_state() { + $completionclass = \mod_forum\completion\custom_completion::class; + throw new coding_exception(__FUNCTION__ . "() has been removed, please use the '{$completionclass}' class instead"); } /** diff --git a/mod/glossary/deprecatedlib.php b/mod/glossary/deprecatedlib.php index fb830480070..48048c601b8 100644 --- a/mod/glossary/deprecatedlib.php +++ b/mod/glossary/deprecatedlib.php @@ -23,39 +23,9 @@ */ /** - * Obtains the automatic completion state for this glossary based on any conditions - * in glossary settings. - * * @deprecated since Moodle 3.11 - * @todo MDL-71196 Final deprecation in Moodle 4.3 - * @see \mod_glossary\completion\custom_completion - * @param stdClass $course Course - * @param cm_info|stdClass $cm Course-module - * @param int $userid User ID - * @param bool $type Type of comparison (or/and; can be used as return value if no conditions) - * @return bool True if completed, false if not. (If no conditions, then return value depends on comparison type) */ -function glossary_get_completion_state($course, $cm, $userid, $type) { - global $DB; - - // No need to call debugging here. Deprecation debugging notice already being called in \completion_info::internal_get_state(). - - // Get glossary details. - if (!($glossary = $DB->get_record('glossary', array('id' => $cm->instance)))) { - throw new Exception("Can't find glossary {$cm->instance}"); - } - - $result = $type; // Default return value. - - if ($glossary->completionentries) { - $value = $glossary->completionentries <= - $DB->count_records('glossary_entries', array('glossaryid' => $glossary->id, 'userid' => $userid, 'approved' => 1)); - if ($type == COMPLETION_AND) { - $result = $result && $value; - } else { - $result = $result || $value; - } - } - - return $result; +function glossary_get_completion_state() { + $completionclass = \mod_glossary\completion\custom_completion::class; + throw new coding_exception(__FUNCTION__ . "() has been removed, please use the '{$completionclass}' class instead"); } diff --git a/mod/lesson/deprecatedlib.php b/mod/lesson/deprecatedlib.php index e7255972c7c..b1929f66a34 100644 --- a/mod/lesson/deprecatedlib.php +++ b/mod/lesson/deprecatedlib.php @@ -23,51 +23,9 @@ */ /** - * Obtains the automatic completion state for this lesson based on any conditions - * in lesson settings. - * * @deprecated since Moodle 3.11 - * @todo MDL-71196 Final deprecation in Moodle 4.3 - * @see \mod_lesson\completion\custom_completion - * @param stdClass $course Course - * @param cm_info|stdClass $cm course-module - * @param int $userid User ID - * @param bool $type Type of comparison (or/and; can be used as return value if no conditions) - * @return bool True if completed, false if not, $type if conditions not set. */ -function lesson_get_completion_state($course, $cm, $userid, $type) { - global $DB; - - // No need to call debugging here. Deprecation debugging notice already being called in \completion_info::internal_get_state(). - - // Get lesson details. - $lesson = $DB->get_record('lesson', array('id' => $cm->instance), '*', MUST_EXIST); - - $result = $type; // Default return value. - // If completion option is enabled, evaluate it and return true/false. - if ($lesson->completionendreached) { - $value = $DB->record_exists('lesson_timer', array('lessonid' => $lesson->id, 'userid' => $userid, 'completed' => 1)); - if ($type == COMPLETION_AND) { - $result = $result && $value; - } else { - $result = $result || $value; - } - } - if ($lesson->completiontimespent != 0) { - $duration = $DB->get_field_sql( - "SELECT SUM(lessontime - starttime) - FROM {lesson_timer} - WHERE lessonid = :lessonid - AND userid = :userid", - array('userid' => $userid, 'lessonid' => $lesson->id)); - if (!$duration) { - $duration = 0; - } - if ($type == COMPLETION_AND) { - $result = $result && ($lesson->completiontimespent < $duration); - } else { - $result = $result || ($lesson->completiontimespent < $duration); - } - } - return $result; +function lesson_get_completion_state() { + $completionclass = \mod_lesson\completion\custom_completion::class; + throw new coding_exception(__FUNCTION__ . "() has been removed, please use the '{$completionclass}' class instead"); } diff --git a/mod/quiz/deprecatedlib.php b/mod/quiz/deprecatedlib.php index 05f3dd39fa2..a155f74d52c 100644 --- a/mod/quiz/deprecatedlib.php +++ b/mod/quiz/deprecatedlib.php @@ -27,114 +27,11 @@ use mod_quiz\quiz_settings; use mod_quiz\task\update_overdue_attempts; /** - * Internal function used in quiz_get_completion_state. Check passing grade (or no attempts left) requirement for completion. - * * @deprecated since Moodle 3.11 - * @todo MDL-71196 Final deprecation in Moodle 4.3 - * @see \mod_quiz\completion\custom_completion - * @param stdClass $course - * @param cm_info|stdClass $cm - * @param int $userid - * @param stdClass $quiz - * @return bool True if the passing grade (or no attempts left) requirement is disabled or met. - * @throws coding_exception */ -function quiz_completion_check_passing_grade_or_all_attempts($course, $cm, $userid, $quiz) { - global $CFG; - - debugging('quiz_completion_check_passing_grade_or_all_attempts has been deprecated.', DEBUG_DEVELOPER); - - if (!$cm->completionpassgrade) { - return true; - } - - // Check for passing grade. - require_once($CFG->libdir . '/gradelib.php'); - $item = grade_item::fetch(['courseid' => $course->id, 'itemtype' => 'mod', - 'itemmodule' => 'quiz', 'iteminstance' => $cm->instance, 'outcomeid' => null]); - if ($item) { - $grades = grade_grade::fetch_users_grades($item, [$userid], false); - if (!empty($grades[$userid]) && $grades[$userid]->is_passed($item)) { - return true; - } - } - - // If a passing grade is required and exhausting all available attempts is not accepted for completion, - // then this quiz is not complete. - if (!$quiz->completionattemptsexhausted) { - return false; - } - - // Check if all attempts are used up. - $attempts = quiz_get_user_attempts($quiz->id, $userid, 'finished', true); - if (!$attempts) { - return false; - } - $lastfinishedattempt = end($attempts); - $context = context_module::instance($cm->id); - $quizobj = quiz_settings::create($quiz->id, $userid); - $accessmanager = new access_manager($quizobj, time(), - has_capability('mod/quiz:ignoretimelimits', $context, $userid, false)); - - return $accessmanager->is_finished(count($attempts), $lastfinishedattempt); -} - -/** - * Internal function used in quiz_get_completion_state. Check minimum attempts requirement for completion. - * - * @deprecated since Moodle 3.11 - * @todo MDL-71196 Final deprecation in Moodle 4.3 - * @see \mod_quiz\completion\custom_completion - * @param int $userid - * @param stdClass $quiz - * @return bool True if minimum attempts requirement is disabled or met. - */ -function quiz_completion_check_min_attempts($userid, $quiz) { - - debugging('quiz_completion_check_min_attempts has been deprecated.', DEBUG_DEVELOPER); - - if (empty($quiz->completionminattempts)) { - return true; - } - - // Check if the user has done enough attempts. - $attempts = quiz_get_user_attempts($quiz->id, $userid, 'finished', true); - return $quiz->completionminattempts <= count($attempts); -} - -/** - * Obtains the automatic completion state for this quiz on any conditions - * in quiz settings, such as if all attempts are used or a certain grade is achieved. - * - * @deprecated since Moodle 3.11 - * @todo MDL-71196 Final deprecation in Moodle 4.3 - * @see \mod_quiz\completion\custom_completion - * @param stdClass $course Course - * @param cm_info|stdClass $cm Course-module - * @param int $userid User ID - * @param bool $type Type of comparison (or/and; can be used as return value if no conditions) - * @return bool True if completed, false if not. (If no conditions, then return - * value depends on comparison type) - */ -function quiz_get_completion_state($course, $cm, $userid, $type) { - global $DB; - - // No need to call debugging here. Deprecation debugging notice already being called in \completion_info::internal_get_state(). - - $quiz = $DB->get_record('quiz', ['id' => $cm->instance], '*', MUST_EXIST); - if (!$quiz->completionattemptsexhausted && !$cm->completionpassgrade && !$quiz->completionminattempts) { - return $type; - } - - if (!quiz_completion_check_passing_grade_or_all_attempts($course, $cm, $userid, $quiz)) { - return false; - } - - if (!quiz_completion_check_min_attempts($userid, $quiz)) { - return false; - } - - return true; +function quiz_get_completion_state() { + $completionclass = \mod_quiz\completion\custom_completion::class; + throw new coding_exception(__FUNCTION__ . "() has been removed, please use the '{$completionclass}' class instead"); } /** diff --git a/mod/quiz/tests/lib_test.php b/mod/quiz/tests/lib_test.php index 3dacaf663c7..53b598a0b0d 100644 --- a/mod/quiz/tests/lib_test.php +++ b/mod/quiz/tests/lib_test.php @@ -134,299 +134,6 @@ class lib_test extends \advanced_testcase { $this->assertEquals(0, $count); } - /** - * Setup function for all test_quiz_get_completion_state_* tests. - * - * @param array $completionoptions ['nbstudents'] => int, ['qtype'] => string, ['quizoptions'] => array - * @throws dml_exception - * @return array [$course, $students, $quiz, $cm] - */ - private function setup_quiz_for_testing_completion(array $completionoptions) { - global $CFG, $DB; - - $this->resetAfterTest(true); - - // Enable completion before creating modules, otherwise the completion data is not written in DB. - $CFG->enablecompletion = true; - - // Create a course and students. - $studentrole = $DB->get_record('role', ['shortname' => 'student']); - $course = $this->getDataGenerator()->create_course(['enablecompletion' => true]); - $students = []; - for ($i = 0; $i < $completionoptions['nbstudents']; $i++) { - $students[$i] = $this->getDataGenerator()->create_user(); - $this->assertTrue($this->getDataGenerator()->enrol_user($students[$i]->id, $course->id, $studentrole->id)); - } - - // Make a quiz. - $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz'); - $data = array_merge([ - 'course' => $course->id, - 'grade' => 100.0, - 'questionsperpage' => 0, - 'sumgrades' => 1, - 'completion' => COMPLETION_TRACKING_AUTOMATIC - ], $completionoptions['quizoptions']); - $quiz = $quizgenerator->create_instance($data); - $cm = get_coursemodule_from_id('quiz', $quiz->cmid); - - // Create a question. - $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question'); - - $cat = $questiongenerator->create_question_category(); - $question = $questiongenerator->create_question($completionoptions['qtype'], null, ['category' => $cat->id]); - quiz_add_quiz_question($question->id, $quiz); - - // Set grade to pass. - $item = \grade_item::fetch(['courseid' => $course->id, 'itemtype' => 'mod', 'itemmodule' => 'quiz', - 'iteminstance' => $quiz->id, 'outcomeid' => null]); - $item->gradepass = 80; - $item->update(); - - return [ - $course, - $students, - $quiz, - $cm - ]; - } - - /** - * Helper function for all test_quiz_get_completion_state_* tests. - * Starts an attempt, processes responses and finishes the attempt. - * - * @param $attemptoptions ['quiz'] => object, ['student'] => object, ['tosubmit'] => array, ['attemptnumber'] => int - */ - private function do_attempt_quiz($attemptoptions) { - $quizobj = quiz_settings::create($attemptoptions['quiz']->id); - - // Start the passing attempt. - $quba = \question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context()); - $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour); - - $timenow = time(); - $attempt = quiz_create_attempt($quizobj, $attemptoptions['attemptnumber'], false, $timenow, false, - $attemptoptions['student']->id); - quiz_start_new_attempt($quizobj, $quba, $attempt, $attemptoptions['attemptnumber'], $timenow); - quiz_attempt_save_started($quizobj, $quba, $attempt); - - // Process responses from the student. - $attemptobj = quiz_attempt::create($attempt->id); - $attemptobj->process_submitted_actions($timenow, false, $attemptoptions['tosubmit']); - - // Finish the attempt. - $attemptobj = quiz_attempt::create($attempt->id); - $this->assertTrue($attemptobj->has_response_to_at_least_one_graded_question()); - $attemptobj->process_finish($timenow, false); - } - - /** - * Test checking the completion state of a quiz. - * The quiz requires a passing grade to be completed. - */ - public function test_quiz_get_completion_state_completionpass() { - - list($course, $students, $quiz, $cm) = $this->setup_quiz_for_testing_completion([ - 'nbstudents' => 2, - 'qtype' => 'numerical', - 'quizoptions' => [ - 'completionusegrade' => 1, - 'completionpassgrade' => 1 - ] - ]); - - list($passstudent, $failstudent) = $students; - - // Do a passing attempt. - $this->do_attempt_quiz([ - 'quiz' => $quiz, - 'student' => $passstudent, - 'attemptnumber' => 1, - 'tosubmit' => [1 => ['answer' => '3.14']] - ]); - - // Check the results. - $this->assertTrue(quiz_get_completion_state($course, $cm, $passstudent->id, 'return')); - - // Do a failing attempt. - $this->do_attempt_quiz([ - 'quiz' => $quiz, - 'student' => $failstudent, - 'attemptnumber' => 1, - 'tosubmit' => [1 => ['answer' => '0']] - ]); - - // Check the results. - $this->assertFalse(quiz_get_completion_state($course, $cm, $failstudent->id, 'return')); - - $this->assertDebuggingCalledCount(3, [ - 'quiz_completion_check_passing_grade_or_all_attempts has been deprecated.', - 'quiz_completion_check_min_attempts has been deprecated.', - 'quiz_completion_check_passing_grade_or_all_attempts has been deprecated.', - ]); - } - - /** - * Test checking the completion state of a quiz. - * To be completed, this quiz requires either a passing grade or for all attempts to be used up. - */ - public function test_quiz_get_completion_state_completionexhausted() { - - list($course, $students, $quiz, $cm) = $this->setup_quiz_for_testing_completion([ - 'nbstudents' => 2, - 'qtype' => 'numerical', - 'quizoptions' => [ - 'attempts' => 2, - 'completionusegrade' => 1, - 'completionpassgrade' => 1, - 'completionattemptsexhausted' => 1 - ] - ]); - - list($passstudent, $exhauststudent) = $students; - - // Start a passing attempt. - $this->do_attempt_quiz([ - 'quiz' => $quiz, - 'student' => $passstudent, - 'attemptnumber' => 1, - 'tosubmit' => [1 => ['answer' => '3.14']] - ]); - - // Check the results. Quiz is completed by $passstudent because of passing grade. - $this->assertTrue(quiz_get_completion_state($course, $cm, $passstudent->id, 'return')); - - // Do a failing attempt. - $this->do_attempt_quiz([ - 'quiz' => $quiz, - 'student' => $exhauststudent, - 'attemptnumber' => 1, - 'tosubmit' => [1 => ['answer' => '0']] - ]); - - // Check the results. Quiz is not completed by $exhauststudent yet because of failing grade and of remaining attempts. - $this->assertFalse(quiz_get_completion_state($course, $cm, $exhauststudent->id, 'return')); - - // Do a second failing attempt. - $this->do_attempt_quiz([ - 'quiz' => $quiz, - 'student' => $exhauststudent, - 'attemptnumber' => 2, - 'tosubmit' => [1 => ['answer' => '0']] - ]); - - // Check the results. Quiz is completed by $exhauststudent because there are no remaining attempts. - $this->assertTrue(quiz_get_completion_state($course, $cm, $exhauststudent->id, 'return')); - - $this->assertDebuggingCalledCount(5, [ - 'quiz_completion_check_passing_grade_or_all_attempts has been deprecated.', - 'quiz_completion_check_min_attempts has been deprecated.', - 'quiz_completion_check_passing_grade_or_all_attempts has been deprecated.', - 'quiz_completion_check_passing_grade_or_all_attempts has been deprecated.', - 'quiz_completion_check_min_attempts has been deprecated.', - ]); - } - - /** - * Test checking the completion state of a quiz. - * To be completed, this quiz requires a minimum number of attempts. - */ - public function test_quiz_get_completion_state_completionminattempts() { - - list($course, $students, $quiz, $cm) = $this->setup_quiz_for_testing_completion([ - 'nbstudents' => 1, - 'qtype' => 'essay', - 'quizoptions' => [ - 'completionminattemptsenabled' => 1, - 'completionminattempts' => 2 - ] - ]); - - list($student) = $students; - - // Do a first attempt. - $this->do_attempt_quiz([ - 'quiz' => $quiz, - 'student' => $student, - 'attemptnumber' => 1, - 'tosubmit' => [1 => ['answer' => 'Lorem ipsum.', 'answerformat' => '1']] - ]); - - // Check the results. Quiz is not completed yet because only one attempt was done. - $this->assertFalse(quiz_get_completion_state($course, $cm, $student->id, 'return')); - - // Do a second attempt. - $this->do_attempt_quiz([ - 'quiz' => $quiz, - 'student' => $student, - 'attemptnumber' => 2, - 'tosubmit' => [1 => ['answer' => 'Lorem ipsum.', 'answerformat' => '1']] - ]); - - // Check the results. Quiz is completed by $student because two attempts were done. - $this->assertTrue(quiz_get_completion_state($course, $cm, $student->id, 'return')); - - $this->assertDebuggingCalledCount(4, [ - 'quiz_completion_check_passing_grade_or_all_attempts has been deprecated.', - 'quiz_completion_check_min_attempts has been deprecated.', - 'quiz_completion_check_passing_grade_or_all_attempts has been deprecated.', - 'quiz_completion_check_min_attempts has been deprecated.', - ]); - } - - /** - * Test checking the completion state of a quiz. - * To be completed, this quiz requires a minimum number of attempts AND a passing grade. - * This is somewhat of an edge case as it is hard to imagine a scenario in which these precise settings are useful. - * Nevertheless, this test makes sure these settings interact as intended. - */ - public function test_quiz_get_completion_state_completionminattempts_pass() { - - list($course, $students, $quiz, $cm) = $this->setup_quiz_for_testing_completion([ - 'nbstudents' => 1, - 'qtype' => 'numerical', - 'quizoptions' => [ - 'attempts' => 2, - 'completionusegrade' => 1, - 'completionpassgrade' => 1, - 'completionminattemptsenabled' => 1, - 'completionminattempts' => 2 - ] - ]); - - list($student) = $students; - - // Start a first attempt. - $this->do_attempt_quiz([ - 'quiz' => $quiz, - 'student' => $student, - 'attemptnumber' => 1, - 'tosubmit' => [1 => ['answer' => '3.14']] - ]); - - // Check the results. Even though one requirement is met (passing grade) quiz is not completed yet because only - // one attempt was done. - $this->assertFalse(quiz_get_completion_state($course, $cm, $student->id, 'return')); - - // Start a second attempt. - $this->do_attempt_quiz([ - 'quiz' => $quiz, - 'student' => $student, - 'attemptnumber' => 2, - 'tosubmit' => [1 => ['answer' => '42']] - ]); - - // Check the results. Quiz is completed by $student because two attempts were done AND a passing grade was obtained. - $this->assertTrue(quiz_get_completion_state($course, $cm, $student->id, 'return')); - - $this->assertDebuggingCalledCount(4, [ - 'quiz_completion_check_passing_grade_or_all_attempts has been deprecated.', - 'quiz_completion_check_min_attempts has been deprecated.', - 'quiz_completion_check_passing_grade_or_all_attempts has been deprecated.', - 'quiz_completion_check_min_attempts has been deprecated.', - ]); - } - public function test_quiz_get_user_attempts() { global $DB; $this->resetAfterTest(); diff --git a/mod/scorm/deprecatedlib.php b/mod/scorm/deprecatedlib.php index 114a4acb634..e52562a923d 100644 --- a/mod/scorm/deprecatedlib.php +++ b/mod/scorm/deprecatedlib.php @@ -23,119 +23,9 @@ */ /** - * Obtains the automatic completion state for this scorm based on any conditions - * in scorm settings. - * * @deprecated since Moodle 3.11 - * @todo MDL-71196 Final deprecation in Moodle 4.3 - * @see \mod_scorm\completion\custom_completion - * @param stdClass $course Course - * @param cm_info|stdClass $cm Course-module - * @param int $userid User ID - * @param bool $type Type of comparison (or/and; can be used as return value if no conditions) - * @return bool True if completed, false if not. (If no conditions, then return - * value depends on comparison type) */ -function scorm_get_completion_state($course, $cm, $userid, $type) { - global $DB; - - // No need to call debugging here. Deprecation debugging notice already being called in \completion_info::internal_get_state(). - - $result = $type; - - // Get scorm. - if (!$scorm = $DB->get_record('scorm', array('id' => $cm->instance))) { - throw new \moodle_exception('cannotfindscorm'); - } - // Only check for existence of tracks and return false if completionstatusrequired or completionscorerequired - // this means that if only view is required we don't end up with a false state. - if ($scorm->completionstatusrequired !== null || $scorm->completionscorerequired !== null) { - // Get user's tracks data. - $tracks = $DB->get_records_sql( - " - SELECT - v.id, - v.scoid, - e.element, - v.value - FROM - {scorm_scoes_value} v - JOIN {scorm_attempt} a on a.id = v.attemptid - JOIN {scorm_element} e on e.id = v.elementid - WHERE - a.scormid = ? - AND a.userid = ? - AND e.element IN - ( - 'cmi.core.lesson_status', - 'cmi.completion_status', - 'cmi.success_status', - 'cmi.core.score.raw', - 'cmi.score.raw' - ) - ", - array($scorm->id, $userid) - ); - - if (!$tracks) { - return completion_info::aggregate_completion_states($type, $result, false); - } - } - - // Check for status. - if ($scorm->completionstatusrequired !== null) { - - // Get status. - $statuses = array_flip(scorm_status_options()); - $nstatus = 0; - // Check any track for these values. - $scostatus = array(); - foreach ($tracks as $track) { - if (!in_array($track->element, array('cmi.core.lesson_status', 'cmi.completion_status', 'cmi.success_status'))) { - continue; - } - if (array_key_exists($track->value, $statuses)) { - $scostatus[$track->scoid] = true; - $nstatus |= $statuses[$track->value]; - } - } - - if (!empty($scorm->completionstatusallscos)) { - // Iterate over all scos and make sure each has a lesson_status. - $scos = $DB->get_records('scorm_scoes', array('scorm' => $scorm->id, 'scormtype' => 'sco')); - foreach ($scos as $sco) { - if (empty($scostatus[$sco->id])) { - return completion_info::aggregate_completion_states($type, $result, false); - } - } - return completion_info::aggregate_completion_states($type, $result, true); - } else if ($scorm->completionstatusrequired & $nstatus) { - return completion_info::aggregate_completion_states($type, $result, true); - } else { - return completion_info::aggregate_completion_states($type, $result, false); - } - } - - // Check for score. - if ($scorm->completionscorerequired !== null) { - $maxscore = -1; - - foreach ($tracks as $track) { - if (!in_array($track->element, array('cmi.core.score.raw', 'cmi.score.raw'))) { - continue; - } - - if (strlen($track->value) && floatval($track->value) >= $maxscore) { - $maxscore = floatval($track->value); - } - } - - if ($scorm->completionscorerequired <= $maxscore) { - return completion_info::aggregate_completion_states($type, $result, true); - } else { - return completion_info::aggregate_completion_states($type, $result, false); - } - } - - return $result; +function scorm_get_completion_state() { + $completionclass = \mod_scorm\completion\custom_completion::class; + throw new coding_exception(__FUNCTION__ . "() has been removed, please use the '{$completionclass}' class instead"); } diff --git a/mod/survey/deprecatedlib.php b/mod/survey/deprecatedlib.php index 23bd4b7170b..4f522ffe206 100644 --- a/mod/survey/deprecatedlib.php +++ b/mod/survey/deprecatedlib.php @@ -23,32 +23,9 @@ */ /** - * Obtains the automatic completion state for this survey based on the condition - * in feedback settings. - * * @deprecated since Moodle 3.11 - * @todo MDL-71196 Final deprecation in Moodle 4.3 - * @see \mod_survey\completion\custom_completion - * @param stdClass $course Course - * @param cm_info|stdClass $cm Course-module - * @param int $userid User ID - * @param bool $type Type of comparison (or/and; can be used as return value if no conditions) - * @return bool True if completed, false if not, $type if conditions not set. */ -function survey_get_completion_state($course, $cm, $userid, $type) { - global $DB; - - // No need to call debugging here. Deprecation debugging notice already being called in \completion_info::internal_get_state(). - - // Get survey details. - $survey = $DB->get_record('survey', array('id' => $cm->instance), '*', MUST_EXIST); - - // If completion option is enabled, evaluate it and return true/false. - if ($survey->completionsubmit) { - $params = array('userid' => $userid, 'survey' => $survey->id); - return $DB->record_exists('survey_answers', $params); - } else { - // Completion option is not enabled so just return $type. - return $type; - } +function survey_get_completion_state() { + $completionclass = \mod_survey\completion\custom_completion::class; + throw new coding_exception(__FUNCTION__ . "() has been removed, please use the '{$completionclass}' class instead"); }