public static function process_course_module_deleted(\core\event\course_module_deleted $event) { global $CFG, $DB; require_once $CFG->dirroot . "/local/morph/classes/logger/Logger.php"; require_once $CFG->dirroot . "/mod/project/projectadminlib.php"; $log = new moodle\local\morph\Logger(array("prefix" => 'project_')); $log->debug("OBSERVED COURSE MODULE CREATED DELETED"); $eventdata = $event->get_data(); if ($eventdata['other']['modulename'] === 'project') { $other = $eventdata["other"]; $projectid = $other['instanceid']; if ($project_tools = $DB->get_record('project_tools', array('project_id' => $projectid))) { $chat_cm = get_coursemodule_from_instance("chat", $project_tools->chat_id); $DB->delete_records('chat', array('id' => $chat_cm->instance)); $DB->delete_records('course_modules', array('id' => $chat_cm->id)); $forum_cm = get_coursemodule_from_instance("forum", $project_tools->forum_id); $DB->delete_records('forum', array('id' => $forum_cm->instance)); $DB->delete_records('course_modules', array('id' => $forum_cm->id)); } $log->debug("DELETED PROJECT"); } }
/** * This function will handles the whole deletion process of a module. This includes calling * the modules delete_instance function, deleting files, events, grades, conditional data, * the data in the course_module and course_sections table and adding a module deletion * event to the DB. * * @param int $cmid the course module id * @since 2.5 */ function course_delete_module($cmid) { global $CFG, $DB; require_once $CFG->libdir . '/gradelib.php'; require_once $CFG->dirroot . '/blog/lib.php'; require_once $CFG->dirroot . '/calendar/lib.php'; // Get the course module. if (!($cm = $DB->get_record('course_modules', array('id' => $cmid)))) { return true; } // Get the module context. $modcontext = context_module::instance($cm->id); // Get the course module name. $modulename = $DB->get_field('modules', 'name', array('id' => $cm->module), MUST_EXIST); // Get the file location of the delete_instance function for this module. $modlib = "{$CFG->dirroot}/mod/{$modulename}/lib.php"; // Include the file required to call the delete_instance function for this module. if (file_exists($modlib)) { require_once $modlib; } else { throw new moodle_exception('cannotdeletemodulemissinglib', '', '', null, "Cannot delete this module as the file mod/{$modulename}/lib.php is missing."); } $deleteinstancefunction = $modulename . '_delete_instance'; // Ensure the delete_instance function exists for this module. if (!function_exists($deleteinstancefunction)) { throw new moodle_exception('cannotdeletemodulemissingfunc', '', '', null, "Cannot delete this module as the function {$modulename}_delete_instance is missing in mod/{$modulename}/lib.php."); } // Call the delete_instance function, if it returns false throw an exception. if (!$deleteinstancefunction($cm->instance)) { throw new moodle_exception('cannotdeletemoduleinstance', '', '', null, "Cannot delete the module {$modulename} (instance)."); } // Remove all module files in case modules forget to do that. $fs = get_file_storage(); $fs->delete_area_files($modcontext->id); // Delete events from calendar. if ($events = $DB->get_records('event', array('instance' => $cm->instance, 'modulename' => $modulename))) { foreach ($events as $event) { $calendarevent = calendar_event::load($event->id); $calendarevent->delete(); } } // Delete grade items, outcome items and grades attached to modules. if ($grade_items = grade_item::fetch_all(array('itemtype' => 'mod', 'itemmodule' => $modulename, 'iteminstance' => $cm->instance, 'courseid' => $cm->course))) { foreach ($grade_items as $grade_item) { $grade_item->delete('moddelete'); } } // Delete completion and availability data; it is better to do this even if the // features are not turned on, in case they were turned on previously (these will be // very quick on an empty table). $DB->delete_records('course_modules_completion', array('coursemoduleid' => $cm->id)); $DB->delete_records('course_modules_availability', array('coursemoduleid' => $cm->id)); $DB->delete_records('course_modules_avail_fields', array('coursemoduleid' => $cm->id)); $DB->delete_records('course_completion_criteria', array('moduleinstance' => $cm->id, 'criteriatype' => COMPLETION_CRITERIA_TYPE_ACTIVITY)); // Delete the context. context_helper::delete_instance(CONTEXT_MODULE, $cm->id); // Delete the module from the course_modules table. $DB->delete_records('course_modules', array('id' => $cm->id)); // Delete module from that section. if (!delete_mod_from_section($cm->id, $cm->section)) { throw new moodle_exception('cannotdeletemodulefromsection', '', '', null, "Cannot delete the module {$modulename} (instance) from section."); } // Trigger event for course module delete action. $event = \core\event\course_module_deleted::create(array('courseid' => $cm->course, 'context' => $modcontext, 'objectid' => $cm->id, 'other' => array('modulename' => $modulename, 'instanceid' => $cm->instance))); $event->add_record_snapshot('course_modules', $cm); $event->trigger(); rebuild_course_cache($cm->course, true); }
/** * Tests for event validations related to course module deletion. */ public function test_course_module_deleted_event_exceptions() { $this->resetAfterTest(); // Generate data. $modinfo = $this->create_specific_module_test('assign'); $context = context_module::instance($modinfo->coursemodule); // Test not setting instanceid. try { $event = \core\event\course_module_deleted::create(array('courseid' => $modinfo->course, 'context' => $context, 'objectid' => $modinfo->coursemodule, 'other' => array('modulename' => 'assign', 'name' => 'My assignment'))); $this->fail("Event validation should not allow \\core\\event\\course_module_deleted to be triggered without\n other['instanceid']"); } catch (coding_exception $e) { $this->assertContains("The 'instanceid' value must be set in other.", $e->getMessage()); } // Test not setting modulename. try { $event = \core\event\course_module_deleted::create(array('courseid' => $modinfo->course, 'context' => $context, 'objectid' => $modinfo->coursemodule, 'other' => array('instanceid' => $modinfo->instance, 'name' => 'My assignment'))); $this->fail("Event validation should not allow \\core\\event\\course_module_deleted to be triggered without\n other['modulename']"); } catch (coding_exception $e) { $this->assertContains("The 'modulename' value must be set in other.", $e->getMessage()); } }
/** * This function will handle the whole deletion process of a module. This includes calling * the modules delete_instance function, deleting files, events, grades, conditional data, * the data in the course_module and course_sections table and adding a module deletion * event to the DB. * * @param int $cmid the course module id * @param bool $async whether or not to try to delete the module using an adhoc task. Async also depends on a plugin hook. * @throws moodle_exception * @since Moodle 2.5 */ function course_delete_module($cmid, $async = false) { // Check the 'course_module_background_deletion_recommended' hook first. // Only use asynchronous deletion if at least one plugin returns true and if async deletion has been requested. // Both are checked because plugins should not be allowed to dictate the deletion behaviour, only support/decline it. // It's up to plugins to handle things like whether or not they are enabled. if ($async && ($pluginsfunction = get_plugins_with_function('course_module_background_deletion_recommended'))) { foreach ($pluginsfunction as $plugintype => $plugins) { foreach ($plugins as $pluginfunction) { if ($pluginfunction()) { return course_module_flag_for_async_deletion($cmid); } } } } global $CFG, $DB; require_once $CFG->libdir . '/gradelib.php'; require_once $CFG->libdir . '/questionlib.php'; require_once $CFG->dirroot . '/blog/lib.php'; require_once $CFG->dirroot . '/calendar/lib.php'; // Get the course module. if (!($cm = $DB->get_record('course_modules', array('id' => $cmid)))) { return true; } // Get the module context. $modcontext = context_module::instance($cm->id); // Get the course module name. $modulename = $DB->get_field('modules', 'name', array('id' => $cm->module), MUST_EXIST); // Get the file location of the delete_instance function for this module. $modlib = "{$CFG->dirroot}/mod/{$modulename}/lib.php"; // Include the file required to call the delete_instance function for this module. if (file_exists($modlib)) { require_once $modlib; } else { throw new moodle_exception('cannotdeletemodulemissinglib', '', '', null, "Cannot delete this module as the file mod/{$modulename}/lib.php is missing."); } $deleteinstancefunction = $modulename . '_delete_instance'; // Ensure the delete_instance function exists for this module. if (!function_exists($deleteinstancefunction)) { throw new moodle_exception('cannotdeletemodulemissingfunc', '', '', null, "Cannot delete this module as the function {$modulename}_delete_instance is missing in mod/{$modulename}/lib.php."); } // Allow plugins to use this course module before we completely delete it. if ($pluginsfunction = get_plugins_with_function('pre_course_module_delete')) { foreach ($pluginsfunction as $plugintype => $plugins) { foreach ($plugins as $pluginfunction) { $pluginfunction($cm); } } } // Delete activity context questions and question categories. question_delete_activity($cm); // Call the delete_instance function, if it returns false throw an exception. if (!$deleteinstancefunction($cm->instance)) { throw new moodle_exception('cannotdeletemoduleinstance', '', '', null, "Cannot delete the module {$modulename} (instance)."); } // Remove all module files in case modules forget to do that. $fs = get_file_storage(); $fs->delete_area_files($modcontext->id); // Delete events from calendar. if ($events = $DB->get_records('event', array('instance' => $cm->instance, 'modulename' => $modulename))) { foreach ($events as $event) { $calendarevent = calendar_event::load($event->id); $calendarevent->delete(); } } // Delete grade items, outcome items and grades attached to modules. if ($grade_items = grade_item::fetch_all(array('itemtype' => 'mod', 'itemmodule' => $modulename, 'iteminstance' => $cm->instance, 'courseid' => $cm->course))) { foreach ($grade_items as $grade_item) { $grade_item->delete('moddelete'); } } // Delete completion and availability data; it is better to do this even if the // features are not turned on, in case they were turned on previously (these will be // very quick on an empty table). $DB->delete_records('course_modules_completion', array('coursemoduleid' => $cm->id)); $DB->delete_records('course_completion_criteria', array('moduleinstance' => $cm->id, 'course' => $cm->course, 'criteriatype' => COMPLETION_CRITERIA_TYPE_ACTIVITY)); // Delete all tag instances associated with the instance of this module. core_tag_tag::delete_instances('mod_' . $modulename, null, $modcontext->id); core_tag_tag::remove_all_item_tags('core', 'course_modules', $cm->id); // Notify the competency subsystem. \core_competency\api::hook_course_module_deleted($cm); // Delete the context. context_helper::delete_instance(CONTEXT_MODULE, $cm->id); // Delete the module from the course_modules table. $DB->delete_records('course_modules', array('id' => $cm->id)); // Delete module from that section. if (!delete_mod_from_section($cm->id, $cm->section)) { throw new moodle_exception('cannotdeletemodulefromsection', '', '', null, "Cannot delete the module {$modulename} (instance) from section."); } // Trigger event for course module delete action. $event = \core\event\course_module_deleted::create(array('courseid' => $cm->course, 'context' => $modcontext, 'objectid' => $cm->id, 'other' => array('modulename' => $modulename, 'instanceid' => $cm->instance))); $event->add_record_snapshot('course_modules', $cm); $event->trigger(); rebuild_course_cache($cm->course, true); }