diff --git a/lib/completionlib.php b/lib/completionlib.php index db3abebf00e..2258259f865 100644 --- a/lib/completionlib.php +++ b/lib/completionlib.php @@ -498,7 +498,16 @@ class completion_info { */ public function clear_criteria() { global $DB; - $DB->delete_records('course_completion_criteria', array('course' => $this->course_id)); + + // Remove completion criteria records for the course itself, and any records that refer to the course. + $select = 'course = :course OR (criteriatype = :type AND courseinstance = :courseinstance)'; + $params = [ + 'course' => $this->course_id, + 'type' => COMPLETION_CRITERIA_TYPE_COURSE, + 'courseinstance' => $this->course_id, + ]; + + $DB->delete_records_select('course_completion_criteria', $select, $params); $DB->delete_records('course_completion_aggr_methd', array('course' => $this->course_id)); $this->delete_course_completion_data(); diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php index 6ce95684d97..558f346ffe6 100644 --- a/lib/db/upgrade.php +++ b/lib/db/upgrade.php @@ -2212,5 +2212,16 @@ function xmldb_main_upgrade($oldversion) { upgrade_main_savepoint(true, 2020013000.01); } + if ($oldversion < 2020040200.01) { + // Clean up completion criteria records referring to courses that no longer exist. + $select = 'criteriatype = :type AND courseinstance NOT IN (SELECT id FROM {course})'; + $params = ['type' => 8]; // COMPLETION_CRITERIA_TYPE_COURSE. + + $DB->delete_records_select('course_completion_criteria', $select, $params); + + // Main savepoint reached. + upgrade_main_savepoint(true, 2020040200.01); + } + return true; } diff --git a/lib/tests/completionlib_test.php b/lib/tests/completionlib_test.php index 208aeb1d751..53e4071882f 100644 --- a/lib/tests/completionlib_test.php +++ b/lib/tests/completionlib_test.php @@ -875,6 +875,44 @@ class core_completionlib_testcase extends advanced_testcase { $this->assertFalse($c2->has_activities()); } + /** + * Test that data is cleaned up when we delete courses that are set as completion criteria for other courses + * + * @return void + */ + public function test_course_delete_prerequisite() { + global $DB; + + $this->setup_data(); + + $courseprerequisite = $this->getDataGenerator()->create_course(['enablecompletion' => true]); + + $criteriadata = (object) [ + 'id' => $this->course->id, + 'criteria_course' => [$courseprerequisite->id], + ]; + + /** @var completion_criteria_course $criteria */ + $criteria = completion_criteria::factory(['criteriatype' => COMPLETION_CRITERIA_TYPE_COURSE]); + $criteria->update_config($criteriadata); + + // Sanity test. + $this->assertTrue($DB->record_exists('course_completion_criteria', [ + 'course' => $this->course->id, + 'criteriatype' => COMPLETION_CRITERIA_TYPE_COURSE, + 'courseinstance' => $courseprerequisite->id, + ])); + + // Deleting the prerequisite course should remove the completion criteria. + delete_course($courseprerequisite, false); + + $this->assertFalse($DB->record_exists('course_completion_criteria', [ + 'course' => $this->course->id, + 'criteriatype' => COMPLETION_CRITERIA_TYPE_COURSE, + 'courseinstance' => $courseprerequisite->id, + ])); + } + /** * Test course module completion update event. */ diff --git a/version.php b/version.php index bbed55d9341..d2a1eb8c66e 100644 --- a/version.php +++ b/version.php @@ -29,7 +29,7 @@ defined('MOODLE_INTERNAL') || die(); -$version = 2020040200.00; // YYYYMMDD = weekly release date of this DEV branch. +$version = 2020040200.01; // YYYYMMDD = weekly release date of this DEV branch. // RR = release increments - 00 in DEV branches. // .XX = incremental changes. $release = '3.9dev (Build: 20200402)'; // Human-friendly version name