diff --git a/lang/en/moodle.php b/lang/en/moodle.php index 6844d5fd3a8..3cf6a99a0f4 100644 --- a/lang/en/moodle.php +++ b/lang/en/moodle.php @@ -771,6 +771,12 @@ $string['eventuserloggedout'] = 'User logged out'; $string['eventuserpasswordupdated'] = 'User password updated'; $string['eventuserprofileviewed'] = 'User profile viewed'; $string['eventuserupdated'] = 'User updated'; +$string['eventuserinfofieldcreated'] = 'User profile field created'; +$string['eventuserinfofieldupdated'] = 'User profile field updated'; +$string['eventuserinfofielddeleted'] = 'User profile field deleted'; +$string['eventuserinfocategorycreated'] = 'User profile field category created'; +$string['eventuserinfocategoryupdated'] = 'User profile field category updated'; +$string['eventuserinfocategorydeleted'] = 'User profile field category deleted'; $string['everybody'] = 'Everybody'; $string['executeat'] = 'Execute at'; $string['existing'] = 'Existing'; diff --git a/lib/classes/event/user_info_category_created.php b/lib/classes/event/user_info_category_created.php new file mode 100644 index 00000000000..e8d2692ee74 --- /dev/null +++ b/lib/classes/event/user_info_category_created.php @@ -0,0 +1,128 @@ +. + +/** + * User profile field created event. + * + * @package core + * @copyright 2017 Web Courseworks, Ltd. {@link http://www.webcourseworks.com} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core\event; + +defined('MOODLE_INTERNAL') || die(); + +/** + * User profile info category created event. + * + * @property-read array $other { + * Extra information about event. + * + * - string name: the name of the field. + * } + * + * @package core + * @copyright 2017 Web Courseworks, Ltd. {@link http://www.webcourseworks.com} + * @since Moodle 3.4 + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class user_info_category_created extends base { + + /** + * Initialise the event data. + */ + protected function init() { + $this->data['objecttable'] = 'user_info_category'; + $this->data['crud'] = 'c'; + $this->data['edulevel'] = self::LEVEL_OTHER; + } + + /** + * Creates an event from a profile info category. + * + * @since Moodle 3.4 + * @param \stdClass $category A sna[pshot of the created category. + * @return \core\event\base + */ + public static function create_from_category($category) { + $event = self::create(array( + 'objectid' => $category->id, + 'context' => \context_system::instance(), + 'other' => array( + 'name' => $category->name, + ) + )); + + $event->add_record_snapshot('user_info_category', $category); + + return $event; + } + + /** + * Returns localised event name. + * + * @return string + */ + public static function get_name() { + return get_string('eventuserinfocategorycreated'); + } + + /** + * Returns non-localised event description with id's for admin use only. + * + * @return string + */ + public function get_description() { + $name = s($this->other['name']); + return "The user with id '$this->userid' created the user profile field category '$name' with id '$this->objectid'."; + } + + /** + * Returns relevant URL. + * + * @return \moodle_url + */ + public function get_url() { + return new \moodle_url('/user/profile/index.php', array( + 'action' => 'editcategory', + 'id' => $this->objectid + )); + } + + /** + * Custom validation. + * + * @throws \coding_exception + * @return void + */ + protected function validate_data() { + parent::validate_data(); + + if (!isset($this->other['name'])) { + throw new \coding_exception('The \'name\' value must be set in other.'); + } + } + + /** + * Get the backup/restore table mapping for this event. + * + * @return string + */ + public static function get_objectid_mapping() { + return base::NOT_MAPPED; + } +} diff --git a/lib/classes/event/user_info_category_deleted.php b/lib/classes/event/user_info_category_deleted.php new file mode 100644 index 00000000000..01db25bc94e --- /dev/null +++ b/lib/classes/event/user_info_category_deleted.php @@ -0,0 +1,115 @@ +. + +/** + * User profile field deleted event. + * + * @package core + * @copyright 2017 Web Courseworks, Ltd. {@link http://www.webcourseworks.com} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +namespace core\event; + +defined('MOODLE_INTERNAL') || die(); + +/** + * User deleted event class. + * + * @property-read array $other { + * Extra information about event. + * + * - string name: the name of the field. + * } + * + * @package core + * @copyright 2017 Web Courseworks, Ltd. {@link http://www.webcourseworks.com} + * @since Moodle 3.4 + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class user_info_category_deleted extends base { + + /** + * Initialise required event data properties. + */ + protected function init() { + $this->data['objecttable'] = 'user_info_category'; + $this->data['crud'] = 'd'; + $this->data['edulevel'] = self::LEVEL_OTHER; + } + + /** + * Creates an event from a profile info category. + * + * @since Moodle 3.4 + * @param \stdClass $category A snapshot of the deleted category. + * @return \core\event\base + */ + public static function create_from_category($category) { + $event = self::create(array( + 'objectid' => $category->id, + 'context' => \context_system::instance(), + 'other' => array( + 'name' => $category->name, + ) + )); + + $event->add_record_snapshot('user_info_category', $category); + + return $event; + } + + /** + * Returns localised event name. + * + * @return string + */ + public static function get_name() { + return get_string('eventuserinfocategorydeleted'); + } + + /** + * Returns non-localised event description with id's for admin use only. + * + * @return string + */ + public function get_description() { + $name = s($this->other['name']); + return "The user with id '$this->userid' deleted the user profile field category '$name' with id '$this->objectid'."; + } + + /** + * Custom validation. + * + * @throws \coding_exception + * @return void + */ + protected function validate_data() { + parent::validate_data(); + + if (!isset($this->other['name'])) { + throw new \coding_exception('The \'name\' value must be set in other.'); + } + } + + /** + * Get the backup/restore table mapping for this event. + * + * @return string + */ + public static function get_objectid_mapping() { + return base::NOT_MAPPED; + } +} \ No newline at end of file diff --git a/lib/classes/event/user_info_category_updated.php b/lib/classes/event/user_info_category_updated.php new file mode 100644 index 00000000000..e2ebb5fca97 --- /dev/null +++ b/lib/classes/event/user_info_category_updated.php @@ -0,0 +1,128 @@ +. + +/** + * User profile field updated event. + * + * @package core + * @copyright 2017 Web Courseworks, Ltd. {@link http://www.webcourseworks.com} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core\event; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Event when user profile is updated. + * + * @property-read array $other { + * Extra information about event. + * + * - string name: the name of the field. + * } + * + * @package core + * @copyright 2017 Web Courseworks, Ltd. {@link http://www.webcourseworks.com} + * @since Moodle 3.4 + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class user_info_category_updated extends base { + + /** + * Initialise the event data. + */ + protected function init() { + $this->data['objecttable'] = 'user_info_category'; + $this->data['crud'] = 'u'; + $this->data['edulevel'] = self::LEVEL_OTHER; + } + + /** + * Creates an event from a profile info category. + * + * @since Moodle 3.4 + * @param \stdClass $category A snapshot of the updated category. + * @return \core\event\base + */ + public static function create_from_category($category) { + $event = self::create(array( + 'objectid' => $category->id, + 'context' => \context_system::instance(), + 'other' => array( + 'name' => $category->name, + ) + )); + + $event->add_record_snapshot('user_info_category', $category); + + return $event; + } + + /** + * Returns localised event name. + * + * @return string + */ + public static function get_name() { + return get_string('eventuserinfocategoryupdated'); + } + + /** + * Returns non-localised event description with id's for admin use only. + * + * @return string + */ + public function get_description() { + $name = s($this->other['name']); + return "The user with id '$this->userid' updated the user profile field category '$name' with id '$this->objectid'."; + } + + /** + * Returns relevant URL. + * + * @return \moodle_url + */ + public function get_url() { + return new \moodle_url('/user/profile/index.php', array( + 'action' => 'editcategory', + 'id' => $this->objectid + )); + } + + /** + * Custom validation. + * + * @throws \coding_exception + * @return void + */ + protected function validate_data() { + parent::validate_data(); + + if (!isset($this->other['name'])) { + throw new \coding_exception('The \'name\' value must be set in other.'); + } + } + + /** + * Get the backup/restore table mapping for this event. + * + * @return string + */ + public static function get_objectid_mapping() { + return base::NOT_MAPPED; + } +} diff --git a/lib/classes/event/user_info_field_created.php b/lib/classes/event/user_info_field_created.php new file mode 100644 index 00000000000..8e1a4b6b8ce --- /dev/null +++ b/lib/classes/event/user_info_field_created.php @@ -0,0 +1,141 @@ +. + +/** + * User profile field created event. + * + * @package core + * @copyright 2017 Web Courseworks, Ltd. {@link http://www.webcourseworks.com} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core\event; + +defined('MOODLE_INTERNAL') || die(); + +/** + * User profile info field created event. + * + * @property-read array $other { + * Extra information about event. + * + * - string shortname: the shortname of the field. + * - string name: the name of the field. + * - string datatype: the data type of the field. + * } + * + * @package core + * @copyright 2017 Web Courseworks, Ltd. {@link http://www.webcourseworks.com} + * @since Moodle 3.4 + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class user_info_field_created extends base { + + /** + * Initialise the event data. + */ + protected function init() { + $this->data['objecttable'] = 'user_info_field'; + $this->data['crud'] = 'c'; + $this->data['edulevel'] = self::LEVEL_OTHER; + } + + /** + * Creates an event from a profile field. + * + * @since Moodle 3.4 + * @param \stdClass $field A snapshot of the created field. + * @return \core\event\base + */ + public static function create_from_field($field) { + $event = self::create(array( + 'objectid' => $field->id, + 'context' => \context_system::instance(), + 'other' => array( + 'shortname' => $field->shortname, + 'name' => $field->name, + 'datatype' => $field->datatype, + ) + )); + + $event->add_record_snapshot('user_info_field', $field); + + return $event; + } + + /** + * Returns localised event name. + * + * @return string + */ + public static function get_name() { + return get_string('eventuserinfofieldcreated'); + } + + /** + * Returns non-localised event description with id's for admin use only. + * + * @return string + */ + public function get_description() { + $name = s($this->other['name']); + return "The user with id '$this->userid' created the user profile field '$name' with id '$this->objectid'."; + } + + /** + * Returns relevant URL. + * + * @return \moodle_url + */ + public function get_url() { + return new \moodle_url('/user/profile/index.php', array( + 'action' => 'editfield', + 'id' => $this->objectid, + 'datatype' => $this->other['datatype'] + )); + } + + /** + * Custom validation. + * + * @throws \coding_exception + * @return void + */ + protected function validate_data() { + parent::validate_data(); + + if (!isset($this->other['shortname'])) { + throw new \coding_exception('The \'shortname\' value must be set in other.'); + } + + if (!isset($this->other['name'])) { + throw new \coding_exception('The \'name\' value must be set in other.'); + } + + if (!isset($this->other['datatype'])) { + throw new \coding_exception('The \'datatype\' value must be set in other.'); + } + } + + /** + * Get the backup/restore table mapping for this event. + * + * @return string + */ + public static function get_objectid_mapping() { + return base::NOT_MAPPED; + } +} diff --git a/lib/classes/event/user_info_field_deleted.php b/lib/classes/event/user_info_field_deleted.php new file mode 100644 index 00000000000..a3af8c757da --- /dev/null +++ b/lib/classes/event/user_info_field_deleted.php @@ -0,0 +1,127 @@ +. + +/** + * User profile info field deleted event. + * + * @package core + * @copyright 2017 Web Courseworks, Ltd. {@link http://www.webcourseworks.com} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +namespace core\event; + +defined('MOODLE_INTERNAL') || die(); + +/** + * User profile info field deleted event. + * + * @property-read array $other { + * Extra information about event. + * + * - string shortname: the shortname of the field. + * - string name: the name of the field. + * - string datatype: the data type of the field. + * } + * + * @package core + * @copyright 2017 Web Courseworks, Ltd. {@link http://www.webcourseworks.com} + * @since Moodle 3.4 + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class user_info_field_deleted extends base { + + /** + * Initialise required event data properties. + */ + protected function init() { + $this->data['objecttable'] = 'user_info_field'; + $this->data['crud'] = 'd'; + $this->data['edulevel'] = self::LEVEL_OTHER; + } + + /** + * Creates an event from a profile field. + * + * @since Moodle 3.4 + * @param \stdClass $field A snapshot of the deleted field. + * @return \core\event\base + */ + public static function create_from_field($field) { + $event = self::create(array( + 'objectid' => $field->id, + 'context' => \context_system::instance(), + 'other' => array( + 'shortname' => $field->shortname, + 'name' => $field->name, + 'datatype' => $field->datatype, + ) + )); + + $event->add_record_snapshot('user_info_field', $field); + + return $event; + } + + /** + * Returns localised event name. + * + * @return string + */ + public static function get_name() { + return get_string('eventuserinfofielddeleted'); + } + + /** + * Returns non-localised event description with id's for admin use only. + * + * @return string + */ + public function get_description() { + $name = s($this->other['name']); + return "The user with id '$this->userid' deleted the user profile field '$name' with id '$this->objectid'."; + } + + /** + * Custom validation. + * + * @throws \coding_exception + * @return void + */ + protected function validate_data() { + parent::validate_data(); + + if (!isset($this->other['shortname'])) { + throw new \coding_exception('The \'shortname\' value must be set in other.'); + } + + if (!isset($this->other['name'])) { + throw new \coding_exception('The \'name\' value must be set in other.'); + } + + if (!isset($this->other['datatype'])) { + throw new \coding_exception('The \'datatype\' value must be set in other.'); + } + } + + /** + * Get the backup/restore table mapping for this event. + * + * @return string + */ + public static function get_objectid_mapping() { + return base::NOT_MAPPED; + } +} \ No newline at end of file diff --git a/lib/classes/event/user_info_field_updated.php b/lib/classes/event/user_info_field_updated.php new file mode 100644 index 00000000000..270de986da1 --- /dev/null +++ b/lib/classes/event/user_info_field_updated.php @@ -0,0 +1,141 @@ +. + +/** + * User profile info field updated event. + * + * @package core + * @copyright 2017 Web Courseworks, Ltd. {@link http://www.webcourseworks.com} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core\event; + +defined('MOODLE_INTERNAL') || die(); + +/** + * User profile info field updated event. + * + * @property-read array $other { + * Extra information about event. + * + * - string shortname: the shortname of the field. + * - string name: the name of the field. + * - string datatype: the data type of the field. + * } + * + * @package core + * @copyright 2017 Web Courseworks, Ltd. {@link http://www.webcourseworks.com} + * @since Moodle 3.4 + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class user_info_field_updated extends base { + + /** + * Initialise the event data. + */ + protected function init() { + $this->data['objecttable'] = 'user_info_field'; + $this->data['crud'] = 'u'; + $this->data['edulevel'] = self::LEVEL_OTHER; + } + + /** + * Creates an event from a profile field. + * + * @since Moodle 3.4 + * @param \stdClass $field A snapshot of the updated field. + * @return \core\event\base + */ + public static function create_from_field($field) { + $event = self::create(array( + 'objectid' => $field->id, + 'context' => \context_system::instance(), + 'other' => array( + 'shortname' => $field->shortname, + 'name' => $field->name, + 'datatype' => $field->datatype, + ) + )); + + $event->add_record_snapshot('user_info_field', $field); + + return $event; + } + + /** + * Returns localised event name. + * + * @return string + */ + public static function get_name() { + return get_string('eventuserinfofieldupdated'); + } + + /** + * Returns non-localised event description with id's for admin use only. + * + * @return string + */ + public function get_description() { + $name = s($this->other['name']); + return "The user with id '$this->userid' updated the user profile field '$name' with id '$this->objectid'."; + } + + /** + * Returns relevant URL. + * + * @return \moodle_url + */ + public function get_url() { + return new \moodle_url('/user/profile/index.php', array( + 'action' => 'editfield', + 'id' => $this->objectid, + 'datatype' => $this->other['datatype'] + )); + } + + /** + * Custom validation. + * + * @throws \coding_exception + * @return void + */ + protected function validate_data() { + parent::validate_data(); + + if (!isset($this->other['shortname'])) { + throw new \coding_exception('The \'shortname\' value must be set in other.'); + } + + if (!isset($this->other['name'])) { + throw new \coding_exception('The \'name\' value must be set in other.'); + } + + if (!isset($this->other['datatype'])) { + throw new \coding_exception('The \'datatype\' value must be set in other.'); + } + } + + /** + * Get the backup/restore table mapping for this event. + * + * @return string + */ + public static function get_objectid_mapping() { + return base::NOT_MAPPED; + } +} diff --git a/lib/tests/event_profile_field_test.php b/lib/tests/event_profile_field_test.php new file mode 100644 index 00000000000..9536068bd1d --- /dev/null +++ b/lib/tests/event_profile_field_test.php @@ -0,0 +1,393 @@ +. + +/** + * Tests the events related to the user profile fields and categories. + * + * @package core + * @category test + * @copyright 2017 Mark Nelson + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +global $CFG; + +require_once($CFG->dirroot . '/user/profile/definelib.php'); + +/** + * Tests the events related to the user profile fields and categories. + * + * @package core + * @category test + * @copyright 2017 Mark Nelson + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class core_event_profile_field_testcase extends advanced_testcase { + + /** + * Test set up. + */ + public function setUp() { + $this->resetAfterTest(); + } + + /** + * Test that triggering the user_info_category_created event works as expected. + */ + public function test_user_info_category_created_event() { + global $DB; + + // Create a new profile category. + $cat1 = new stdClass(); + $cat1->name = 'Example category'; + $cat1->sortorder = 1; + $cat1->id = $DB->insert_record('user_info_category', $cat1); + + // Trigger the event. + $sink = $this->redirectEvents(); + \core\event\user_info_category_created::create_from_category($cat1)->trigger(); + $events = $sink->get_events(); + $sink->close(); + + // Confirm we got the right number of events. + $this->assertCount(1, $events); + + // Validate that the event was correctly triggered. + $event = reset($events); + $this->assertInstanceOf('\core\event\user_info_category_created', $event); + $this->assertEquals($event->objectid, $cat1->id); + $this->assertEquals($event->other['name'], $cat1->name); + } + + /** + * Test that moving a user info category triggers an updated event. + */ + public function test_user_info_category_updated_event() { + global $DB; + + // Create new profile categories. + $cat1 = new stdClass(); + $cat1->name = 'Example category'; + $cat1->sortorder = 1; + $cat1->id = $DB->insert_record('user_info_category', $cat1); + + $cat2 = new stdClass(); + $cat2->name = 'Example category 2'; + $cat2->sortorder = 2; + $cat2->id = $DB->insert_record('user_info_category', $cat2); + + // Trigger the events. + $sink = $this->redirectEvents(); + profile_move_category($cat1->id, 'down'); + $events = $sink->get_events(); + $sink->close(); + + // Should now have two events. + $this->assertCount(2, $events); + $event1 = array_shift($events); + $event2 = array_shift($events); + + // Validate that the events were correctly triggered. + $this->assertInstanceOf('\core\event\user_info_category_updated', $event1); + $this->assertEquals($event1->objectid, $cat1->id); + $this->assertEquals($event1->other['name'], $cat1->name); + + $this->assertInstanceOf('\core\event\user_info_category_updated', $event2); + $this->assertEquals($event2->objectid, $cat2->id); + $this->assertEquals($event2->other['name'], $cat2->name); + } + + /** + * Test that deleting a user info category triggers a delete event. + */ + public function test_user_info_category_deleted_event() { + global $DB; + + // Create new profile categories. + $cat1 = new stdClass(); + $cat1->name = 'Example category'; + $cat1->sortorder = 1; + $cat1->id = $DB->insert_record('user_info_category', $cat1); + + $cat2 = new stdClass(); + $cat2->name = 'Example category 2'; + $cat2->sortorder = 2; + $cat2->id = $DB->insert_record('user_info_category', $cat2); + + // Trigger the event. + $sink = $this->redirectEvents(); + profile_delete_category($cat2->id); + $events = $sink->get_events(); + $sink->close(); + + // Confirm we got the right number of events. + $this->assertCount(1, $events); + + // Validate that the event was correctly triggered. + $event = reset($events); + $this->assertInstanceOf('\core\event\user_info_category_deleted', $event); + $this->assertEquals($event->objectid, $cat2->id); + $this->assertEquals($event->other['name'], $cat2->name); + } + + /** + * Test that creating a user info field triggers a create event. + */ + public function test_user_info_field_created_event() { + global $DB; + + // Create a new profile category. + $cat1 = new stdClass(); + $cat1->name = 'Example category'; + $cat1->sortorder = 1; + $cat1->id = $DB->insert_record('user_info_category', $cat1); + + // Create a new profile field. + $data = new stdClass(); + $data->datatype = 'text'; + $data->shortname = 'example'; + $data->name = 'Example field'; + $data->description = 'Hello this is an example.'; + $data->required = false; + $data->locked = false; + $data->forceunique = false; + $data->signup = false; + $data->visible = '0'; + $data->categoryid = $cat1->id; + + // Trigger the event. + $sink = $this->redirectEvents(); + $field = new profile_define_base(); + $field->define_save($data); + $events = $sink->get_events(); + $sink->close(); + + // Get the field that was created. + $field = $DB->get_record('user_info_field', array('shortname' => $data->shortname)); + + // Confirm we got the right number of events. + $this->assertCount(1, $events); + + // Validate that the event was correctly triggered. + $event = reset($events); + $this->assertInstanceOf('\core\event\user_info_field_created', $event); + $this->assertEquals($event->objectid, $field->id); + $this->assertEquals($event->other['shortname'], $field->shortname); + $this->assertEquals($event->other['name'], $field->name); + $this->assertEquals($event->other['datatype'], $field->datatype); + } + + /** + * Test that updating a user info field triggers an update event. + */ + public function test_user_info_field_updated_event() { + global $DB; + + // Create a new profile category. + $cat1 = new stdClass(); + $cat1->name = 'Example category'; + $cat1->sortorder = 1; + $cat1->id = $DB->insert_record('user_info_category', $cat1); + + // Create a new profile field. + $data = new stdClass(); + $data->datatype = 'text'; + $data->shortname = 'example'; + $data->name = 'Example field'; + $data->description = 'Hello this is an example.'; + $data->required = false; + $data->locked = false; + $data->forceunique = false; + $data->signup = false; + $data->visible = '0'; + $data->categoryid = $cat1->id; + $data->id = $DB->insert_record('user_info_field', $data); + + // Trigger the event. + $sink = $this->redirectEvents(); + $field = new profile_define_base(); + $field->define_save($data); + $events = $sink->get_events(); + $sink->close(); + + // Confirm we got the right number of events. + $this->assertCount(1, $events); + + // Validate that the event was correctly triggered. + $event = reset($events); + $this->assertInstanceOf('\core\event\user_info_field_updated', $event); + $this->assertEquals($event->objectid, $data->id); + $this->assertEquals($event->other['shortname'], $data->shortname); + $this->assertEquals($event->other['name'], $data->name); + $this->assertEquals($event->other['datatype'], $data->datatype); + } + + /** + * Test that moving a field triggers update events. + */ + public function test_user_info_field_updated_event_move_field() { + global $DB; + + // Create a new profile category. + $cat1 = new stdClass(); + $cat1->name = 'Example category'; + $cat1->sortorder = 1; + $cat1->id = $DB->insert_record('user_info_category', $cat1); + + // Create a new profile field. + $field1 = new stdClass(); + $field1->datatype = 'text'; + $field1->shortname = 'example'; + $field1->name = 'Example field'; + $field1->description = 'Hello this is an example.'; + $field1->required = false; + $field1->locked = false; + $field1->forceunique = false; + $field1->signup = false; + $field1->visible = '0'; + $field1->categoryid = $cat1->id; + $field1->sortorder = 1; + $field1->id = $DB->insert_record('user_info_field', $field1); + + // Create another that we will be moving. + $field2 = clone $field1; + $field2->datatype = 'text'; + $field2->shortname = 'example2'; + $field2->name = 'Example field 2'; + $field2->sortorder = 2; + $field2->id = $DB->insert_record('user_info_field', $field2); + + // Trigger the events. + $sink = $this->redirectEvents(); + profile_move_field($field2->id, 'up'); + $events = $sink->get_events(); + $sink->close(); + + // Should now have two events. + $this->assertCount(2, $events); + $event1 = array_shift($events); + $event2 = array_shift($events); + + // Validate that the events were correctly triggered. + $this->assertInstanceOf('\core\event\user_info_field_updated', $event1); + $this->assertEquals($event1->objectid, $field2->id); + $this->assertEquals($event1->other['shortname'], $field2->shortname); + $this->assertEquals($event1->other['name'], $field2->name); + $this->assertEquals($event1->other['datatype'], $field2->datatype); + + $this->assertInstanceOf('\core\event\user_info_field_updated', $event2); + $this->assertEquals($event2->objectid, $field1->id); + $this->assertEquals($event2->other['shortname'], $field1->shortname); + $this->assertEquals($event2->other['name'], $field1->name); + $this->assertEquals($event2->other['datatype'], $field1->datatype); + } + + /** + * Test that when we delete a category that contains a field, that the field being moved to + * another category triggers an update event. + */ + public function test_user_info_field_updated_event_delete_category() { + global $DB; + + // Create a new profile category. + $cat1 = new stdClass(); + $cat1->name = 'Example category'; + $cat1->sortorder = 1; + $cat1->id = $DB->insert_record('user_info_category', $cat1); + + $cat2 = new stdClass(); + $cat2->name = 'Example category'; + $cat2->sortorder = 1; + $cat2->id = $DB->insert_record('user_info_category', $cat2); + + // Create a new profile field. + $field = new stdClass(); + $field->datatype = 'text'; + $field->shortname = 'example'; + $field->name = 'Example field'; + $field->description = 'Hello this is an example.'; + $field->required = false; + $field->locked = false; + $field->forceunique = false; + $field->signup = false; + $field->visible = '0'; + $field->categoryid = $cat1->id; + $field->id = $DB->insert_record('user_info_field', $field); + + // Trigger the event. + $sink = $this->redirectEvents(); + profile_delete_category($cat1->id); + $events = $sink->get_events(); + $sink->close(); + + // Check we got the right number of events. + $this->assertCount(2, $events); + + // Validate that the event was correctly triggered. + $event = reset($events); + $this->assertInstanceOf('\core\event\user_info_field_updated', $event); + $this->assertEquals($event->objectid, $field->id); + $this->assertEquals($event->other['shortname'], $field->shortname); + $this->assertEquals($event->other['name'], $field->name); + $this->assertEquals($event->other['datatype'], $field->datatype); + } + + /** + * Test that deleting a user info field triggers a delete event. + */ + public function test_user_info_field_deleted_event() { + global $DB; + + // Create a new profile category. + $cat1 = new stdClass(); + $cat1->name = 'Example category'; + $cat1->sortorder = 1; + $cat1->id = $DB->insert_record('user_info_category', $cat1); + + // Create a new profile field. + $data = new stdClass(); + $data->datatype = 'text'; + $data->shortname = 'delete'; + $data->name = 'Example field for delete'; + $data->description = 'Hello this is an example.'; + $data->required = false; + $data->locked = false; + $data->forceunique = false; + $data->signup = false; + $data->visible = '0'; + $data->categoryid = $cat1->id; + $data->id = $DB->insert_record('user_info_field', $data, true); + + // Trigger the event. + $sink = $this->redirectEvents(); + profile_delete_field($data->id); + $events = $sink->get_events(); + $sink->close(); + + // Confirm we got the right number of events. + $this->assertCount(1, $events); + + // Validate that the event was correctly triggered. + $event = reset($events); + $this->assertInstanceOf('\core\event\user_info_field_deleted', $event); + $this->assertEquals($event->objectid, $data->id); + $this->assertEquals($event->other['shortname'], $data->shortname); + $this->assertEquals($event->other['name'], $data->name); + $this->assertEquals($event->other['datatype'], $data->datatype); + } +} diff --git a/user/profile/definelib.php b/user/profile/definelib.php index a9a1a12c645..dabf9a9b617 100644 --- a/user/profile/definelib.php +++ b/user/profile/definelib.php @@ -187,6 +187,13 @@ class profile_define_base { } else { $DB->update_record('user_info_field', $data); } + + $field = $DB->get_record('user_info_field', array('id' => $data->id)); + if ($old) { + \core\event\user_info_field_updated::create_from_field($field)->trigger(); + } else { + \core\event\user_info_field_created::create_from_field($field)->trigger(); + } } /** @@ -295,7 +302,11 @@ function profile_delete_category($id) { $f->id = $field->id; $f->sortorder = $sortorder++; $f->categoryid = $newcategory->id; - $DB->update_record('user_info_field', $f); + if ($DB->update_record('user_info_field', $f)) { + $field->sortorder = $f->sortorder; + $field->categoryid = $f->categoryid; + \core\event\user_info_field_updated::create_from_field($field)->trigger(); + } } } } @@ -303,6 +314,9 @@ function profile_delete_category($id) { // Finally we get to delete the category. $DB->delete_records('user_info_category', array('id' => $category->id)); profile_reorder_categories(); + + \core\event\user_info_category_deleted::create_from_category($category)->trigger(); + return true; } @@ -324,9 +338,14 @@ function profile_delete_field($id) { // Need to rebuild course cache to update the info. rebuild_course_cache(0, true); + // Prior to the delete, pull the record for the event. + $field = $DB->get_record('user_info_field', array('id' => $id)); + // Try to remove the record from the database. $DB->delete_records('user_info_field', array('id' => $id)); + \core\event\user_info_field_deleted::create_from_field($field)->trigger(); + // Reorder the remaining fields in the same category. profile_reorder_fields(); } @@ -342,7 +361,7 @@ function profile_move_field($id, $move) { global $DB; // Get the field object. - if (!$field = $DB->get_record('user_info_field', array('id' => $id), 'id, sortorder, categoryid')) { + if (!$field = $DB->get_record('user_info_field', array('id' => $id))) { return false; } // Count the number of fields in this category. @@ -359,7 +378,7 @@ function profile_move_field($id, $move) { // Retrieve the field object that is currently residing in the new position. $params = array('categoryid' => $field->categoryid, 'sortorder' => $neworder); - if ($swapfield = $DB->get_record('user_info_field', $params, 'id, sortorder')) { + if ($swapfield = $DB->get_record('user_info_field', $params)) { // Swap the sortorders. $swapfield->sortorder = $field->sortorder; @@ -368,6 +387,9 @@ function profile_move_field($id, $move) { // Update the field records. $DB->update_record('user_info_field', $field); $DB->update_record('user_info_field', $swapfield); + + \core\event\user_info_field_updated::create_from_field($field)->trigger(); + \core\event\user_info_field_updated::create_from_field($swapfield)->trigger(); } profile_reorder_fields(); @@ -384,7 +406,7 @@ function profile_move_field($id, $move) { function profile_move_category($id, $move) { global $DB; // Get the category object. - if (!($category = $DB->get_record('user_info_category', array('id' => $id), 'id, sortorder'))) { + if (!($category = $DB->get_record('user_info_category', array('id' => $id)))) { return false; } @@ -401,14 +423,19 @@ function profile_move_category($id, $move) { } // Retrieve the category object that is currently residing in the new position. - if ($swapcategory = $DB->get_record('user_info_category', array('sortorder' => $neworder), 'id, sortorder')) { + if ($swapcategory = $DB->get_record('user_info_category', array('sortorder' => $neworder))) { // Swap the sortorders. $swapcategory->sortorder = $category->sortorder; $category->sortorder = $neworder; // Update the category records. - $DB->update_record('user_info_category', $category) and $DB->update_record('user_info_category', $swapcategory); + $DB->update_record('user_info_category', $category); + $DB->update_record('user_info_category', $swapcategory); + + \core\event\user_info_category_updated::create_from_category($category)->trigger(); + \core\event\user_info_category_updated::create_from_category($swapcategory)->trigger(); + return true; } @@ -465,9 +492,15 @@ function profile_edit_category($id, $redirect) { if (empty($data->id)) { unset($data->id); $data->sortorder = $DB->count_records('user_info_category') + 1; - $DB->insert_record('user_info_category', $data, false); + $data->id = $DB->insert_record('user_info_category', $data, true); + + $createdcategory = $DB->get_record('user_info_category', array('id' => $data->id)); + \core\event\user_info_category_created::create_from_category($createdcategory)->trigger(); } else { $DB->update_record('user_info_category', $data); + + $updatedcateogry = $DB->get_record('user_info_category', array('id' => $data->id)); + \core\event\user_info_category_updated::create_from_category($updatedcateogry)->trigger(); } profile_reorder_categories(); redirect($redirect);