MDL-78551 core_enrol: Add support for hooks api

This commit is contained in:
Safat
2024-01-04 12:48:02 +11:00
parent 99b7dc147f
commit 968897b653
7 changed files with 309 additions and 82 deletions
@@ -0,0 +1,43 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace core_enrol\hook;
use stdClass;
/**
* Hook after enrolment status is changed.
*
* @package core_enrol
* @copyright 2024 Safat Shahin <safat.shahin@moodle.com>
* @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,
) {
}
}
@@ -0,0 +1,52 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
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 <safat.shahin@moodle.com>
* @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;
}
}
@@ -0,0 +1,59 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace core_enrol\hook;
use stdClass;
use Psr\EventDispatcher\StoppableEventInterface;
/**
* Hook before enrolment instance is deleted.
*
* @package core_enrol
* @copyright 20234 Safat Shahin <safat.shahin@moodle.com>
* @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;
}
}
@@ -0,0 +1,52 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
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 <safat.shahin@moodle.com>
* @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;
}
}
@@ -0,0 +1,56 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace core_enrol\hook;
use stdClass;
/**
* Hook before a user enrolment is updated.
*
* @package core_enrol
* @copyright 2024 Safat Shahin <safat.shahin@moodle.com>
* @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;
}
}
-12
View File
@@ -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);
}
+47 -70
View File
@@ -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) {