From 080c7d471de81bb1ef0ac3e1a56f39a6a15c2a43 Mon Sep 17 00:00:00 2001 From: Marina Glancy Date: Mon, 24 Aug 2015 16:28:57 +0800 Subject: [PATCH 1/2] MDL-44640 enrol: trigger events on instances actions --- enrol/cohort/edit.php | 1 + enrol/guest/lib.php | 1 + enrol/manual/edit.php | 8 +- enrol/paypal/edit.php | 1 + enrol/self/edit.php | 1 + enrol/tests/enrollib_test.php | 60 ++++++++++ enrol/upgrade.txt | 6 + lang/en/enrol.php | 3 + lib/classes/event/enrol_instance_created.php | 109 ++++++++++++++++++ lib/classes/event/enrol_instance_deleted.php | 110 +++++++++++++++++++ lib/classes/event/enrol_instance_updated.php | 110 +++++++++++++++++++ lib/enrollib.php | 14 ++- 12 files changed, 417 insertions(+), 7 deletions(-) create mode 100644 lib/classes/event/enrol_instance_created.php create mode 100644 lib/classes/event/enrol_instance_deleted.php create mode 100644 lib/classes/event/enrol_instance_updated.php diff --git a/enrol/cohort/edit.php b/enrol/cohort/edit.php index b921f15bffd..3affaa9fcfa 100644 --- a/enrol/cohort/edit.php +++ b/enrol/cohort/edit.php @@ -96,6 +96,7 @@ if ($mform->is_cancelled()) { $instance->customint2 = $groupid; } $DB->update_record('enrol', $instance); + \core\event\enrol_instance_updated::create_from_record($instance)->trigger(); } else { // Create a new group for the cohort if requested. if ($data->customint2 == COHORT_CREATE_GROUP) { diff --git a/enrol/guest/lib.php b/enrol/guest/lib.php index 9336e1c2560..f224f0a52d9 100644 --- a/enrol/guest/lib.php +++ b/enrol/guest/lib.php @@ -332,6 +332,7 @@ class enrol_guest_plugin extends enrol_plugin { $instance->password = $data->{'enrol_guest_password_'.$i}; } $DB->update_record('enrol', $instance); + \core\event\enrol_instance_updated::create_from_record($instance)->trigger(); if ($reset) { $context = context_course::instance($course->id); diff --git a/enrol/manual/edit.php b/enrol/manual/edit.php index d6d01e2d123..27e1de79567 100644 --- a/enrol/manual/edit.php +++ b/enrol/manual/edit.php @@ -92,13 +92,13 @@ if ($mform->is_cancelled()) { $instance->notifyall = $data->notifyall; $instance->expirythreshold = $data->expirythreshold; $instance->timemodified = time(); + $markdirty = ($instance->status != $data->status); + $instance->status = $data->status; $DB->update_record('enrol', $instance); + \core\event\enrol_instance_updated::create_from_record($instance)->trigger(); - // Use standard API to update instance status. - if ($instance->status != $data->status) { - $instance = $DB->get_record('enrol', array('id'=>$instance->id)); - $plugin->update_status($instance, $data->status); + if ($markdirty) { $context->mark_dirty(); } diff --git a/enrol/paypal/edit.php b/enrol/paypal/edit.php index 6175b3bc440..9c0541a4d49 100644 --- a/enrol/paypal/edit.php +++ b/enrol/paypal/edit.php @@ -76,6 +76,7 @@ if ($mform->is_cancelled()) { $instance->enrolenddate = $data->enrolenddate; $instance->timemodified = time(); $DB->update_record('enrol', $instance); + \core\event\enrol_instance_updated::create_from_record($instance)->trigger(); if ($reset) { $context->mark_dirty(); diff --git a/enrol/self/edit.php b/enrol/self/edit.php index a339b8e4b1b..f429c394508 100644 --- a/enrol/self/edit.php +++ b/enrol/self/edit.php @@ -109,6 +109,7 @@ if ($mform->is_cancelled()) { $instance->enrolenddate = $data->enrolenddate; $instance->timemodified = time(); $DB->update_record('enrol', $instance); + \core\event\enrol_instance_updated::create_from_record($instance)->trigger(); if ($reset) { $context->mark_dirty(); diff --git a/enrol/tests/enrollib_test.php b/enrol/tests/enrollib_test.php index 61a43922a98..1a88c50c8c2 100644 --- a/enrol/tests/enrollib_test.php +++ b/enrol/tests/enrollib_test.php @@ -362,4 +362,64 @@ class core_enrollib_testcase extends advanced_testcase { $this->assertEventLegacyLogData($expected, $event); $this->assertEventContextNotUsed($event); } + + /** + * Test enrol_instance_created, enrol_instance_updated and enrol_instance_deleted events. + */ + public function test_instance_events() { + global $DB; + + $this->resetAfterTest(true); + + $selfplugin = enrol_get_plugin('self'); + $studentrole = $DB->get_record('role', array('shortname' => 'student')); + + $course = $this->getDataGenerator()->create_course(); + + // Creating enrol instance. + $sink = $this->redirectEvents(); + $instanceid = $selfplugin->add_instance($course, array('status' => ENROL_INSTANCE_ENABLED, + 'name' => 'Test instance 1', + 'customint6' => 1, + 'roleid' => $studentrole->id)); + $events = $sink->get_events(); + $sink->close(); + + $this->assertCount(1, $events); + $event = array_pop($events); + $this->assertInstanceOf('\core\event\enrol_instance_created', $event); + $this->assertEquals(context_course::instance($course->id), $event->get_context()); + $this->assertEquals('self', $event->other['enrol']); + $this->assertEventContextNotUsed($event); + + // Updating enrol instance. + $instance = $DB->get_record('enrol', array('id' => $instanceid)); + $sink = $this->redirectEvents(); + $selfplugin->update_status($instance, ENROL_INSTANCE_DISABLED); + + $events = $sink->get_events(); + $sink->close(); + + $this->assertCount(1, $events); + $event = array_pop($events); + $this->assertInstanceOf('\core\event\enrol_instance_updated', $event); + $this->assertEquals(context_course::instance($course->id), $event->get_context()); + $this->assertEquals('self', $event->other['enrol']); + $this->assertEventContextNotUsed($event); + + // Deleting enrol instance. + $instance = $DB->get_record('enrol', array('id' => $instanceid)); + $sink = $this->redirectEvents(); + $selfplugin->delete_instance($instance); + + $events = $sink->get_events(); + $sink->close(); + + $this->assertCount(1, $events); + $event = array_pop($events); + $this->assertInstanceOf('\core\event\enrol_instance_deleted', $event); + $this->assertEquals(context_course::instance($course->id), $event->get_context()); + $this->assertEquals('self', $event->other['enrol']); + $this->assertEventContextNotUsed($event); + } } diff --git a/enrol/upgrade.txt b/enrol/upgrade.txt index 40f9682d81e..d4090255037 100644 --- a/enrol/upgrade.txt +++ b/enrol/upgrade.txt @@ -1,6 +1,12 @@ This files describes API changes in /enrol/* - plugins, information provided here is intended especially for developers. +=== 3.0 === + +* Added new events enrol_instance_created, enrol_instance_updated and + enrol_instance_deleted . Always trigger them when changing records in the + DB table 'enrol'. + === 2.9 === * External function core_enrol_external::get_users_courses now returns additional optional fields: diff --git a/lang/en/enrol.php b/lang/en/enrol.php index 1ca0a6e1c2f..ec115e262dc 100644 --- a/lang/en/enrol.php +++ b/lang/en/enrol.php @@ -48,6 +48,9 @@ $string['enrolcandidates'] = 'Not enrolled users'; $string['enrolcandidatesmatching'] = 'Matching not enrolled users'; $string['enrolcohort'] = 'Enrol cohort'; $string['enrolcohortusers'] = 'Enrol users'; +$string['eventenrolinstancecreated'] = 'Enrolment instance created'; +$string['eventenrolinstancedeleted'] = 'Enrolment instance deleted'; +$string['eventenrolinstanceupdated'] = 'Enrolment instance updated'; $string['enrollednewusers'] = 'Successfully enrolled {$a} new users'; $string['enrolledusers'] = 'Enrolled users'; $string['enrolledusersmatching'] = 'Matching enrolled users'; diff --git a/lib/classes/event/enrol_instance_created.php b/lib/classes/event/enrol_instance_created.php new file mode 100644 index 00000000000..ba03ea4b0f7 --- /dev/null +++ b/lib/classes/event/enrol_instance_created.php @@ -0,0 +1,109 @@ +. + +/** + * Enrol instance created event. + * + * @package core + * @copyright 2015 Marina Glancy + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core\event; +defined('MOODLE_INTERNAL') || die(); + +/** + * Enrol instance created event class. + * + * @property-read array $other { + * Extra information about event. + * + * - string enrol: name of enrol method + * } + * + * @package core + * @since Moodle 2.9 + * @copyright 2015 Marina Glancy + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class enrol_instance_created extends base { + + /** + * Api to Create new event from enrol object. + * + * @param \stdClass $enrol record from DB table 'enrol' + * @return \core\event\base returns instance of new event + */ + public static final function create_from_record($enrol) { + $event = static::create(array( + 'context' => \context_course::instance($enrol->courseid), + 'objectid' => $enrol->id, + 'other' => array('enrol' => $enrol->enrol) + )); + return $event; + } + + /** + * Returns description of what happened. + * + * @return string + */ + public function get_description() { + return "The user with id '$this->userid' created the instance of enrolment method '" . + $this->other['enrol'] . "' with id '$this->objectid'."; + } + + /** + * Return localised event name. + * + * @return string + */ + public static function get_name() { + return get_string('eventenrolinstancecreated', 'enrol'); + } + + /** + * Get URL related to the action + * + * @return \moodle_url + */ + public function get_url() { + return new \moodle_url('/enrol/instances.php', array('id' => $this->courseid)); + } + + /** + * Init method. + * + * @return void + */ + protected function init() { + $this->data['crud'] = 'c'; + $this->data['edulevel'] = self::LEVEL_OTHER; + $this->data['objecttable'] = 'enrol'; + } + + /** + * custom validations + * + * Throw \coding_exception notice in case of any problems. + */ + protected function validate_data() { + parent::validate_data(); + if (!isset($this->other['enrol'])) { + throw new \coding_exception('The \'enrol\' value must be set in other.'); + } + } +} diff --git a/lib/classes/event/enrol_instance_deleted.php b/lib/classes/event/enrol_instance_deleted.php new file mode 100644 index 00000000000..9c1bf95c7d6 --- /dev/null +++ b/lib/classes/event/enrol_instance_deleted.php @@ -0,0 +1,110 @@ +. + +/** + * Enrol instance deleted event. + * + * @package core + * @copyright 2015 Marina Glancy + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core\event; +defined('MOODLE_INTERNAL') || die(); + +/** + * Enrol instance deleted event class. + * + * @property-read array $other { + * Extra information about event. + * + * - string enrol: name of enrol method + * } + * + * @package core + * @since Moodle 2.9 + * @copyright 2015 Marina Glancy + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class enrol_instance_deleted extends base { + + /** + * Api to Create new event from enrol object. + * + * @param \stdClass $enrol record from DB table 'enrol' + * @return \core\event\base returns instance of new event + */ + public static final function create_from_record($enrol) { + $event = static::create(array( + 'context' => \context_course::instance($enrol->courseid), + 'objectid' => $enrol->id, + 'other' => array('enrol' => $enrol->enrol) + )); + $event->add_record_snapshot('enrol', $enrol); + return $event; + } + + /** + * Returns description of what happened. + * + * @return string + */ + public function get_description() { + return "The user with id '$this->userid' deleted the instance of enrolment method '" . + $this->other['enrol'] . "' with id '$this->objectid'."; + } + + /** + * Return localised event name. + * + * @return string + */ + public static function get_name() { + return get_string('eventgroupingdeleted', 'group'); + } + + /** + * Get URL related to the action + * + * @return \moodle_url + */ + public function get_url() { + return new \moodle_url('/enrol/instances.php', array('id' => $this->courseid)); + } + + /** + * Init method. + * + * @return void + */ + protected function init() { + $this->data['crud'] = 'd'; + $this->data['edulevel'] = self::LEVEL_OTHER; + $this->data['objecttable'] = 'enrol'; + } + + /** + * custom validations + * + * Throw \coding_exception notice in case of any problems. + */ + protected function validate_data() { + parent::validate_data(); + if (!isset($this->other['enrol'])) { + throw new \coding_exception('The \'enrol\' value must be set in other.'); + } + } +} diff --git a/lib/classes/event/enrol_instance_updated.php b/lib/classes/event/enrol_instance_updated.php new file mode 100644 index 00000000000..98732d721d0 --- /dev/null +++ b/lib/classes/event/enrol_instance_updated.php @@ -0,0 +1,110 @@ +. + +/** + * Enrol instance updated event. + * + * @package core + * @copyright 2015 Marina Glancy + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core\event; +defined('MOODLE_INTERNAL') || die(); + +/** + * Enrol instance updated event class. + * + * @property-read array $other { + * Extra information about event. + * + * - string enrol: name of enrol method + * } + * + * @package core + * @since Moodle 2.9 + * @copyright 2015 Marina Glancy + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class enrol_instance_updated extends base { + + /** + * Api to Create new event from enrol object. + * + * @param \stdClass $enrol record from DB table 'enrol' + * @return \core\event\base returns instance of new event + */ + public static final function create_from_record($enrol) { + $event = static::create(array( + 'context' => \context_course::instance($enrol->courseid), + 'objectid' => $enrol->id, + 'other' => array('enrol' => $enrol->enrol) + )); + $event->add_record_snapshot('enrol', $enrol); + return $event; + } + + /** + * Returns description of what happened. + * + * @return string + */ + public function get_description() { + return "The user with id '$this->userid' updated the instance of enrolment method '" . + $this->other['enrol'] . "' with id '$this->objectid'."; + } + + /** + * Return localised event name. + * + * @return string + */ + public static function get_name() { + return get_string('eventenrolinstanceupdated', 'enrol'); + } + + /** + * Get URL related to the action + * + * @return \moodle_url + */ + public function get_url() { + return new \moodle_url('/enrol/instances.php', array('id' => $this->courseid)); + } + + /** + * Init method. + * + * @return void + */ + protected function init() { + $this->data['crud'] = 'u'; + $this->data['edulevel'] = self::LEVEL_OTHER; + $this->data['objecttable'] = 'enrol'; + } + + /** + * custom validations + * + * Throw \coding_exception notice in case of any problems. + */ + protected function validate_data() { + parent::validate_data(); + if (!isset($this->other['enrol'])) { + throw new \coding_exception('The \'enrol\' value must be set in other.'); + } + } +} diff --git a/lib/enrollib.php b/lib/enrollib.php index 67a1cfdd19d..593cafac215 100644 --- a/lib/enrollib.php +++ b/lib/enrollib.php @@ -1692,7 +1692,11 @@ abstract class enrol_plugin { $instance->$field = $value; } - return $DB->insert_record('enrol', $instance); + $instance->id = $DB->insert_record('enrol', $instance); + + \core\event\enrol_instance_created::create_from_record($instance)->trigger(); + + return $instance->id; } /** @@ -1723,8 +1727,10 @@ abstract class enrol_plugin { $instance->status = $newstatus; $DB->update_record('enrol', $instance); - // invalidate all enrol caches $context = context_course::instance($instance->courseid); + \core\event\enrol_instance_updated::create_from_record($instance)->trigger(); + + // Invalidate all enrol caches. $context->mark_dirty(); } @@ -1756,8 +1762,10 @@ abstract class enrol_plugin { // finally drop the enrol row $DB->delete_records('enrol', array('id'=>$instance->id)); - // invalidate all enrol caches $context = context_course::instance($instance->courseid); + \core\event\enrol_instance_deleted::create_from_record($instance)->trigger(); + + // Invalidate all enrol caches. $context->mark_dirty(); } From 7fdc4690483b9fc3bbe06d33baba166921cd1daf Mon Sep 17 00:00:00 2001 From: Marina Glancy Date: Wed, 22 Apr 2015 21:16:52 +0800 Subject: [PATCH 2/2] MDL-44640 enrol_meta: sync when enrol method is updated --- enrol/meta/classes/observer.php | 26 ++++++++++++++++++++++++++ enrol/meta/db/events.php | 4 ++++ enrol/meta/tests/plugin_test.php | 11 +++++++++++ enrol/meta/version.php | 2 +- 4 files changed, 42 insertions(+), 1 deletion(-) diff --git a/enrol/meta/classes/observer.php b/enrol/meta/classes/observer.php index dd62786f8e2..446fca5c8f1 100644 --- a/enrol/meta/classes/observer.php +++ b/enrol/meta/classes/observer.php @@ -204,4 +204,30 @@ class enrol_meta_observer extends enrol_meta_handler { return true; } + + /** + * Triggered via enrol_instance_updated event. + * + * @param \core\event\enrol_instance_updated $event + * @return boolean + */ + public static function enrol_instance_updated(\core\event\enrol_instance_updated $event) { + global $DB; + + if (!enrol_is_enabled('meta')) { + // This is slow, let enrol_meta_sync() deal with disabled plugin. + return true; + } + + // Does anything want to sync with this parent? + $affectedcourses = $DB->get_fieldset_sql('SELECT DISTINCT courseid FROM {enrol} '. + 'WHERE customint1 = ? AND enrol = ?', + array($event->courseid, 'meta')); + + foreach ($affectedcourses as $courseid) { + enrol_meta_sync($courseid); + } + + return true; + } } diff --git a/enrol/meta/db/events.php b/enrol/meta/db/events.php index 8d2a590719e..560aefc990c 100644 --- a/enrol/meta/db/events.php +++ b/enrol/meta/db/events.php @@ -52,4 +52,8 @@ $observers = array( 'eventname' => '\core\event\course_deleted', 'callback' => 'enrol_meta_observer::course_deleted', ), + array( + 'eventname' => '\core\event\enrol_instance_updated', + 'callback' => 'enrol_meta_observer::enrol_instance_updated', + ), ); diff --git a/enrol/meta/tests/plugin_test.php b/enrol/meta/tests/plugin_test.php index 4d3b549393f..9f0fb8a0e24 100644 --- a/enrol/meta/tests/plugin_test.php +++ b/enrol/meta/tests/plugin_test.php @@ -847,6 +847,16 @@ class enrol_meta_plugin_testcase extends advanced_testcase { // Disable manual enrolment in course1 and make sure all user enrolments in course2 are suspended. $manplugin->update_status($manual1, ENROL_INSTANCE_DISABLED); $allsuspendedenrolemnts = array_combine(array_keys($expectedenrolments), array_fill(0, 5, ENROL_USER_SUSPENDED)); + $enrolmentstatuses = $DB->get_records_menu('user_enrolments', array('enrolid' => $meta2id), '', 'userid, status'); + $this->assertEquals($allsuspendedenrolemnts, $enrolmentstatuses); + + $manplugin->update_status($manual1, ENROL_INSTANCE_ENABLED); + $enrolments = $DB->get_records('user_enrolments', array('enrolid' => $meta2id), '', 'userid, timestart, timeend, status'); + $this->assertEquals($expectedenrolments, $enrolments); + + // Disable events and repeat the same for course3 (testing sync): + $sink = $this->redirectEvents(); + $manplugin->update_status($manual1, ENROL_INSTANCE_DISABLED); enrol_meta_sync($course3->id); $enrolmentstatuses = $DB->get_records_menu('user_enrolments', array('enrolid' => $meta3id), '', 'userid, status'); $this->assertEquals($allsuspendedenrolemnts, $enrolmentstatuses); @@ -855,5 +865,6 @@ class enrol_meta_plugin_testcase extends advanced_testcase { enrol_meta_sync($course3->id); $enrolments = $DB->get_records('user_enrolments', array('enrolid' => $meta3id), '', 'userid, timestart, timeend, status'); $this->assertEquals($expectedenrolments, $enrolments); + $sink->close(); } } diff --git a/enrol/meta/version.php b/enrol/meta/version.php index 3df94e1d9ab..83de31ca7ce 100644 --- a/enrol/meta/version.php +++ b/enrol/meta/version.php @@ -24,7 +24,7 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2015051100; // The current plugin version (Date: YYYYMMDDXX) +$plugin->version = 2015082400; // The current plugin version (Date: YYYYMMDDXX) $plugin->requires = 2015050500; // Requires this Moodle version $plugin->component = 'enrol_meta'; // Full name of the plugin (used for diagnostics) $plugin->cron = 60*60; // run cron every hour by default, it is not out-of-sync often