From 14ef8d82f9799f38ddf3a9d35e463a17046d4989 Mon Sep 17 00:00:00 2001 From: Sara Arjona Date: Wed, 21 Jan 2026 08:35:16 +0100 Subject: [PATCH] MDL-87621 subsection: Add API method to clear descriptions --- .upgradenotes/MDL-87621-2026012107393692.yml | 8 ++ public/mod/subsection/classes/manager.php | 39 ++++++ public/mod/subsection/tests/manager_test.php | 134 +++++++++++++++++++ 3 files changed, 181 insertions(+) create mode 100644 .upgradenotes/MDL-87621-2026012107393692.yml diff --git a/.upgradenotes/MDL-87621-2026012107393692.yml b/.upgradenotes/MDL-87621-2026012107393692.yml new file mode 100644 index 00000000000..3ed51459db9 --- /dev/null +++ b/.upgradenotes/MDL-87621-2026012107393692.yml @@ -0,0 +1,8 @@ +issueNumber: MDL-87621 +notes: + mod_subsection: + - message: >- + The `manager::clear_description()` method has been added to remove + legacy data. When called, it deletes the description text associated + with a subsection and any files linked to that description. + type: improved diff --git a/public/mod/subsection/classes/manager.php b/public/mod/subsection/classes/manager.php index 24c32953c00..14a89f356a8 100644 --- a/public/mod/subsection/classes/manager.php +++ b/public/mod/subsection/classes/manager.php @@ -205,4 +205,43 @@ class manager { } return $delegatedsection; } + + /** + * Deletes the subsection description and its associated files. + * Descriptions are no longer supported for subsections since Moodle 5.2. + */ + public function clear_description(): void { + global $DB; + + // Find and delete the files from the subsection summary. + $fs = get_file_storage(); + $coursesectionid = $DB->get_field( + 'course_sections', + 'id', + [ + 'component' => 'mod_subsection', + 'itemid' => $this->instance->id, + ], + ); + $files = $fs->get_area_files( + contextid: \context_course::instance($this->cm->course)->id, + component: 'course', + filearea: 'section', + itemid: $coursesectionid, + ); + foreach ($files as $file) { + $file->delete(); + } + + // Remove the subsection summary. + $DB->set_field( + 'course_sections', + 'summary', + '', + [ + 'component' => 'mod_subsection', + 'itemid' => $this->instance->id, + ], + ); + } } diff --git a/public/mod/subsection/tests/manager_test.php b/public/mod/subsection/tests/manager_test.php index 8f3e3f9f728..343cdf45062 100644 --- a/public/mod/subsection/tests/manager_test.php +++ b/public/mod/subsection/tests/manager_test.php @@ -126,4 +126,138 @@ final class manager_test extends \advanced_testcase { ]; } + + /** + * Test clear_description. + */ + public function test_clear_description(): void { + global $DB; + + $this->resetAfterTest(); + $this->setAdminUser(); + + $course = $this->getDataGenerator()->create_course(); + // Add a couple of subsections with file in the description. + $module1 = $this->getDataGenerator()->create_module('subsection', [ + 'course' => $course->id, + 'section' => 1, + 'summary' => 'Subsection text with link', + ]); + $subsection1 = $DB->get_record( + 'course_sections', + ['course' => $course->id, 'itemid' => $module1->id], + ); + $filerecord = [ + 'component' => 'course', + 'filearea' => 'section', + 'contextid' => \context_course::instance($course->id)->id, + 'itemid' => $subsection1->id, + 'filename' => 'intro1.txt', + 'filepath' => '/', + ]; + $fs = get_file_storage(); + $fs->create_file_from_string($filerecord, 'Test intro file'); + + $module2 = $this->getDataGenerator()->create_module('subsection', [ + 'course' => $course->id, + 'section' => 1, + 'summary' => 'Subsection text with link', + ]); + $subsection2 = $DB->get_record( + 'course_sections', + ['course' => $course->id, 'itemid' => $module2->id], + ); + $filerecord = [ + 'component' => 'course', + 'filearea' => 'section', + 'contextid' => \context_course::instance($course->id)->id, + 'itemid' => $subsection2->id, + 'filename' => 'intro2.txt', + 'filepath' => '/', + ]; + $fs = get_file_storage(); + $fs->create_file_from_string($filerecord, 'Test intro file'); + // Add one more subsection with description but no files. + $module3 = $this->getDataGenerator()->create_module('subsection', [ + 'course' => $course->id, + 'section' => 1, + 'summary' => 'Subsection text with no files', + ]); + + // Check subsections have descriptions. + $this->assertEquals( + 3, + $DB->count_records_select( + 'course_sections', + 'course = :courseid AND component = \'mod_subsection\' AND summary != \'\'', + ['courseid' => $course->id], + ), + ); + $this->assertEquals( + 2, + $DB->count_records_select( + 'files', + 'component = :component AND filearea = :filearea AND (filename != :filename)', + [ + 'component' => 'course', + 'filearea' => 'section', + 'filename' => '.', + ], + ), + ); + + // Clear the description for subsection with files. + $manager = manager::create_from_id($course->id, $module1->id); + $manager->clear_description(); + + // Check only subsection description and its files have been removed. + $this->assertEquals( + 2, + $DB->count_records_select( + 'course_sections', + 'course = :courseid AND component = \'mod_subsection\' AND summary != \'\'', + ['courseid' => $course->id], + ), + ); + // Check the file has been removed too. + $this->assertEquals( + 1, + $DB->count_records_select( + 'files', + 'component = :component AND filearea = :filearea AND (filename != :filename)', + [ + 'component' => 'course', + 'filearea' => 'section', + 'filename' => '.', + ], + ), + ); + + // Clear the description for subsection without files. + $manager = manager::create_from_id($course->id, $module3->id); + $manager->clear_description(); + + // Check only subsection3 description has been removed. + $this->assertEquals( + 1, + $DB->count_records_select( + 'course_sections', + 'course = :courseid AND component = \'mod_subsection\' AND summary != \'\'', + ['courseid' => $course->id], + ), + ); + // Check no files have been removed. + $this->assertEquals( + 1, + $DB->count_records_select( + 'files', + 'component = :component AND filearea = :filearea AND (filename != :filename)', + [ + 'component' => 'course', + 'filearea' => 'section', + 'filename' => '.', + ], + ), + ); + } }