diff --git a/enrol/classes/hook/after_enrol_instance_status_updated.php b/enrol/classes/hook/after_enrol_instance_status_updated.php new file mode 100644 index 00000000000..ceda20103a9 --- /dev/null +++ b/enrol/classes/hook/after_enrol_instance_status_updated.php @@ -0,0 +1,43 @@ +. + +namespace core_enrol\hook; + +use stdClass; + +/** + * Hook after enrolment status is changed. + * + * @package core_enrol + * @copyright 2024 Safat Shahin + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +#[\core\attribute\label('Allows plugins or features to perform actions after the enrolment instance status is changed.')] +#[\core\attribute\tags('enrol')] +class after_enrol_instance_status_updated { + + /** + * Constructor for the hook. + * + * @param stdClass $enrolinstance The enrol instance. + * @param int $newstatus The new status. + */ + public function __construct( + public readonly stdClass $enrolinstance, + public readonly int $newstatus, + ) { + } +} diff --git a/enrol/classes/hook/after_user_enrolled.php b/enrol/classes/hook/after_user_enrolled.php new file mode 100644 index 00000000000..3d00294d310 --- /dev/null +++ b/enrol/classes/hook/after_user_enrolled.php @@ -0,0 +1,52 @@ +. + +namespace core_enrol\hook; + +use stdClass; + +/** + * Hook after a user is enrolled in a course for an enrolment instance. + * + * @package core_enrol + * @copyright 2024 Safat Shahin + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +#[\core\attribute\label('Allows plugins or features to perform actions after a user is enrolled in a course.')] +#[\core\attribute\tags('enrol', 'user')] +class after_user_enrolled { + + /** + * Constructor for the hook. + * + * @param stdClass $enrolinstance The enrol instance. + * @param stdClass $userenrolmentinstance The user enrolment instance. + */ + public function __construct( + public readonly stdClass $enrolinstance, + public readonly stdClass $userenrolmentinstance, + ) { + } + + /** + * Get the user id. + * + * @return int + */ + public function get_userid(): int { + return $this->userenrolmentinstance->userid; + } +} diff --git a/enrol/classes/hook/before_enrol_instance_delete.php b/enrol/classes/hook/before_enrol_instance_delete.php new file mode 100644 index 00000000000..03fff59450e --- /dev/null +++ b/enrol/classes/hook/before_enrol_instance_delete.php @@ -0,0 +1,59 @@ +. + +namespace core_enrol\hook; + +use stdClass; +use Psr\EventDispatcher\StoppableEventInterface; + +/** + * Hook before enrolment instance is deleted. + * + * @package core_enrol + * @copyright 20234 Safat Shahin + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +#[\core\attribute\label('Allows plugins or features to perform actions before the enrolment instance is deleted.')] +#[\core\attribute\tags('enrol')] +class before_enrol_instance_delete implements + StoppableEventInterface { + + /** + * @var bool Whether the propagation of this event has been stopped. + */ + protected bool $stopped = false; + + /** + * Constructor for the hook. + * + * @param stdClass $enrolinstance The enrol instance. + */ + public function __construct( + public readonly stdClass $enrolinstance, + ) { + } + + public function isPropagationStopped(): bool { + return $this->stopped; + } + + /** + * Stop the propagation of this event. + */ + public function stop(): void { + $this->stopped = true; + } +} diff --git a/enrol/classes/hook/before_user_enrolment_remove.php b/enrol/classes/hook/before_user_enrolment_remove.php new file mode 100644 index 00000000000..23df64df94d --- /dev/null +++ b/enrol/classes/hook/before_user_enrolment_remove.php @@ -0,0 +1,52 @@ +. + +namespace core_enrol\hook; + +use stdClass; + +/** + * Hook before a user is un-enrolled from a course for an enrolment instance. + * + * @package core + * @copyright 2024 Safat Shahin + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +#[\core\attribute\label('Allows plugins or features to perform actions before a user enrolment is removed.')] +#[\core\attribute\tags('enrol', 'user')] +class before_user_enrolment_remove { + + /** + * Constructor for the hook. + * + * @param stdClass $enrolinstance The enrol instance. + * @param stdClass $userenrolmentinstance The user enrolment instance. + */ + public function __construct( + public readonly stdClass $enrolinstance, + public readonly stdClass $userenrolmentinstance, + ) { + } + + /** + * Get the user id. + * + * @return int + */ + public function get_userid(): int { + return $this->userenrolmentinstance->userid; + } +} diff --git a/enrol/classes/hook/before_user_enrolment_update.php b/enrol/classes/hook/before_user_enrolment_update.php new file mode 100644 index 00000000000..38d593ed6af --- /dev/null +++ b/enrol/classes/hook/before_user_enrolment_update.php @@ -0,0 +1,56 @@ +. + +namespace core_enrol\hook; + +use stdClass; + +/** + * Hook before a user enrolment is updated. + * + * @package core_enrol + * @copyright 2024 Safat Shahin + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +#[\core\attribute\label('Allows plugins or features to perform actions before a user enrolment is updated.')] +#[\core\attribute\tags('enrol', 'user')] +class before_user_enrolment_update { + + /** + * Constructor for the hook. + * + * @param stdClass $enrolinstance The enrol instance. + * @param stdClass $userenrolmentinstance The user enrolment instance. + * @param bool $statusmodified Whether the status of the enrolment has been modified. + * @param bool $timeendmodified Whether the time end of the enrolment has been modified. + */ + public function __construct( + public readonly stdClass $enrolinstance, + public readonly stdClass $userenrolmentinstance, + public readonly bool $statusmodified, + public readonly bool $timeendmodified, + ) { + } + + /** + * Get the user id. + * + * @return int + */ + public function get_userid(): int { + return $this->userenrolmentinstance->userid; + } +} diff --git a/enrol/instances.php b/enrol/instances.php index dc6103087a4..45e7c376d6a 100644 --- a/enrol/instances.php +++ b/enrol/instances.php @@ -118,10 +118,6 @@ if ($canconfig and $action and confirm_sesskey()) { die(); } } - // Update communication for instance and given action. - if (core_communication\api::is_available() && $instance->enrol !== 'guest') { - $plugin->update_communication($instance->id, 'remove', $course->id); - } $plugin->delete_instance($instance); redirect($PAGE->url); } @@ -172,10 +168,6 @@ if ($canconfig and $action and confirm_sesskey()) { die(); } } - // Update communication for instance and given action. - if (core_communication\api::is_available() && $instance->enrol !== 'guest') { - $plugin->update_communication($instance->id, 'remove', $course->id); - } $plugin->update_status($instance, ENROL_INSTANCE_DISABLED); redirect($PAGE->url); } @@ -187,10 +179,6 @@ if ($canconfig and $action and confirm_sesskey()) { $plugin = $plugins[$instance->enrol]; if ($plugin->can_hide_show_instance($instance)) { if ($instance->status != ENROL_INSTANCE_ENABLED) { - // Update communication for instance and given action. - if (core_communication\api::is_available() && $instance->enrol !== 'guest') { - $plugin->update_communication($instance->id, 'add', $course->id); - } $plugin->update_status($instance, ENROL_INSTANCE_ENABLED); redirect($PAGE->url); } diff --git a/lib/enrollib.php b/lib/enrollib.php index a940bb9c9db..01cd1026c4b 100644 --- a/lib/enrollib.php +++ b/lib/enrollib.php @@ -2156,6 +2156,13 @@ abstract class enrol_plugin { $ue->status, $ue->timestart, $ue->timeend); } + // Dispatch the hook for post enrol user actions. + $hook = new \core_enrol\hook\after_user_enrolled( + enrolinstance: $instance, + userenrolmentinstance: $ue, + ); + \core\di::get(\core\hook\manager::class)->dispatch($hook); + if ($roleid) { // this must be done after the enrolment event so that the role_assigned event is triggered afterwards if ($this->roles_protected()) { @@ -2171,17 +2178,6 @@ abstract class enrol_plugin { grade_recover_history_grades($userid, $courseid); } - // Add users to a communication room. - if (core_communication\api::is_available()) { - $communication = \core_communication\api::load_by_instance( - context: $context, - component: 'core_course', - instancetype: 'coursecommunication', - instanceid: $courseid, - ); - $communication->add_members_to_room([$userid]); - } - // reset current user enrolment caching if ($userid == $USER->id) { if (isset($USER->enrol['enrolled'][$courseid])) { @@ -2241,23 +2237,14 @@ abstract class enrol_plugin { return; } - // Add/remove users to/from communication room. - if (core_communication\api::is_available()) { - $course = enrol_get_course_by_user_enrolment_id($ue->id); - $context = \core\context\course::instance($course->id); - $communication = \core_communication\api::load_by_instance( - context: $context, - component: 'core_course', - instancetype: 'coursecommunication', - instanceid: $course->id, - ); - if (($statusmodified && ((int) $ue->status === 1)) || - ($timeendmodified && $ue->timeend !== 0 && (time() > $ue->timeend))) { - $communication->remove_members_from_room([$userid]); - } else { - $communication->add_members_to_room([$userid]); - } - } + // Dispatch the hook for pre user enrolment update actions. + $hook = new \core_enrol\hook\before_user_enrolment_update( + enrolinstance: $instance, + userenrolmentinstance: $ue, + statusmodified: $statusmodified, + timeendmodified: $timeendmodified, + ); + \core\di::get(\core\hook\manager::class)->dispatch($hook); $ue->modifierid = $USER->id; $ue->timemodified = time(); @@ -2310,6 +2297,13 @@ abstract class enrol_plugin { return; } + // Dispatch the hook for pre user unenrolment actions. + $hook = new \core_enrol\hook\before_user_enrolment_remove( + enrolinstance: $instance, + userenrolmentinstance: $ue, + ); + \core\di::get(\core\hook\manager::class)->dispatch($hook); + // Remove all users groups linked to this enrolment instance. if ($gms = $DB->get_records('groups_members', array('userid'=>$userid, 'component'=>'enrol_'.$name, 'itemid'=>$instance->id))) { foreach ($gms as $gm) { @@ -2361,18 +2355,6 @@ abstract class enrol_plugin { ) ); $event->trigger(); - - // Remove users from a communication room. - if (core_communication\api::is_available()) { - $communication = \core_communication\api::load_by_instance( - context: $context, - component: 'core_course', - instancetype: 'coursecommunication', - instanceid: $courseid, - ); - $communication->remove_members_from_room([$userid]); - } - // User enrolments have changed, so mark user as dirty. mark_user_dirty($userid); @@ -2731,6 +2713,13 @@ abstract class enrol_plugin { $instance->status = $newstatus; $DB->update_record('enrol', $instance); + // Dispatch the hook for post enrol status update actions. + $hook = new \core_enrol\hook\after_enrol_instance_status_updated( + enrolinstance: $instance, + newstatus: $newstatus, + ); + \core\di::get(\core\hook\manager::class)->dispatch($hook); + $context = context_course::instance($instance->courseid); \core\event\enrol_instance_updated::create_from_record($instance)->trigger(); @@ -2743,39 +2732,21 @@ abstract class enrol_plugin { * * Update communication room membership for an instance action being performed. * - * @param int $instanceid ID of the enrolment instance + * @param int $enrolmentinstanceid ID of the enrolment instance * @param string $action The update action being performed - * @param int $courseid The id of the course + * @param stdClass $course The course object * @return void + * @deprecated Since Moodle 4.4.0. + * @see \core_communication\hook_listener::update_communication_memberships_for_enrol_status_change() + * @todo MDL-80491 Final deprecation in Moodle 4.8. + * */ - public function update_communication(int $instanceid, string $action, int $courseid): void { - global $DB; - // Get enrolled instance users. - $instanceusers = $DB->get_records('user_enrolments', ['enrolid' => $instanceid, 'status' => 0]); - $enrolledusers = []; - - foreach ($instanceusers as $user) { - $enrolledusers[] = $user->userid; - } - - $communication = \core_communication\api::load_by_instance( - context: \core\context\course::instance($courseid), - component: 'core_course', - instancetype: 'coursecommunication', - instanceid: $courseid, - ); - - switch ($action) { - case 'add': - $communication->add_members_to_room($enrolledusers); - break; - - case 'remove': - $communication->remove_members_from_room($enrolledusers); - break; - default: - throw new \coding_exception('Invalid action'); - } + public function update_communication(int $enrolmentinstanceid, string $action, stdClass $course): void { + debugging('Use of method update_communication is deprecated. This feature has been moved to + core_communication as a part of hooks api implementation so that plugins or core does not need to call this method anymore. + Method update_communication_memberships_for_enrol_status_change method in communication/classes/hook_listener.php + now handles all the operations related to this method using hooks callback recorded in lib/db/hooks.php.', DEBUG_DEVELOPER); + return; } /** @@ -2791,6 +2762,12 @@ abstract class enrol_plugin { throw new coding_exception('invalid enrol instance!'); } + // Dispatch the hook for pre enrol instance delete actions. + $hook = new \core_enrol\hook\before_enrol_instance_delete( + enrolinstance: $instance, + ); + \core\di::get(\core\hook\manager::class)->dispatch($hook); + //first unenrol all users $participants = $DB->get_recordset('user_enrolments', array('enrolid'=>$instance->id)); foreach ($participants as $participant) {