From 3152de6a8d5eb5db15543e4df4a60176e697eed9 Mon Sep 17 00:00:00 2001 From: Ryan Wyllie Date: Fri, 24 Nov 2017 06:31:53 +0000 Subject: [PATCH] MDL-60963 calendar: use related cache for module instances in export --- .../classes/external/calendar_day_exporter.php | 2 + .../classes/external/calendar_event_exporter.php | 6 +- .../external/calendar_upcoming_exporter.php | 2 + calendar/classes/external/day_exporter.php | 2 + .../external/events_related_objects_cache.php | 67 +++++++++- calendar/classes/external/week_day_exporter.php | 2 + .../tests/events_related_objects_cache_test.php | 140 +++++++++++++++++++++ 7 files changed, 215 insertions(+), 6 deletions(-) create mode 100644 calendar/tests/events_related_objects_cache_test.php diff --git a/calendar/classes/external/calendar_day_exporter.php b/calendar/classes/external/calendar_day_exporter.php index 5869c109bf8..5e0b0cd3381 100644 --- a/calendar/classes/external/calendar_day_exporter.php +++ b/calendar/classes/external/calendar_day_exporter.php @@ -154,9 +154,11 @@ class calendar_day_exporter extends exporter { $return['events'] = array_map(function($event) use ($cache, $output, $url) { $context = $cache->get_context($event); $course = $cache->get_course($event); + $moduleinstance = $cache->get_module_instance($event); $exporter = new calendar_event_exporter($event, [ 'context' => $context, 'course' => $course, + 'moduleinstance' => $moduleinstance, 'daylink' => $url, 'type' => $this->related['type'], 'today' => $this->calendar->time, diff --git a/calendar/classes/external/calendar_event_exporter.php b/calendar/classes/external/calendar_event_exporter.php index ad97c962745..7529e1fb544 100644 --- a/calendar/classes/external/calendar_event_exporter.php +++ b/calendar/classes/external/calendar_event_exporter.php @@ -195,6 +195,7 @@ class calendar_event_exporter extends event_exporter_base { $related['daylink'] = \moodle_url::class; $related['type'] = '\core_calendar\type_base'; $related['today'] = 'int'; + $related['moduleinstance'] = 'stdClass?'; return $related; } @@ -221,14 +222,11 @@ class calendar_event_exporter extends event_exporter_base { * @return array */ protected function get_module_timestamp_limits($event) { - global $DB; - $values = []; $mapper = container::get_event_mapper(); $starttime = $event->get_times()->get_start_time(); $modname = $event->get_course_module()->get('modname'); - $modid = $event->get_course_module()->get('instance'); - $moduleinstance = $DB->get_record($modname, ['id' => $modid]); + $moduleinstance = $this->related['moduleinstance']; list($min, $max) = component_callback( 'mod_' . $modname, diff --git a/calendar/classes/external/calendar_upcoming_exporter.php b/calendar/classes/external/calendar_upcoming_exporter.php index aead6d1dc88..ab05aefecca 100644 --- a/calendar/classes/external/calendar_upcoming_exporter.php +++ b/calendar/classes/external/calendar_upcoming_exporter.php @@ -113,9 +113,11 @@ class calendar_upcoming_exporter extends exporter { $return['events'] = array_map(function($event) use ($cache, $output, $url) { $context = $cache->get_context($event); $course = $cache->get_course($event); + $moduleinstance = $cache->get_module_instance($event); $exporter = new calendar_event_exporter($event, [ 'context' => $context, 'course' => $course, + 'moduleinstance' => $moduleinstance, 'daylink' => $url, 'type' => $this->related['type'], 'today' => $this->calendar->time, diff --git a/calendar/classes/external/day_exporter.php b/calendar/classes/external/day_exporter.php index 3920107b763..7e888b84d44 100644 --- a/calendar/classes/external/day_exporter.php +++ b/calendar/classes/external/day_exporter.php @@ -188,9 +188,11 @@ class day_exporter extends exporter { $eventexporters = array_map(function($event) use ($cache, $output) { $context = $cache->get_context($event); $course = $cache->get_course($event); + $moduleinstance = $cache->get_module_instance($event); $exporter = new calendar_event_exporter($event, [ 'context' => $context, 'course' => $course, + 'moduleinstance' => $moduleinstance, 'daylink' => $this->url, 'type' => $this->related['type'], 'today' => $this->data[0], diff --git a/calendar/classes/external/events_related_objects_cache.php b/calendar/classes/external/events_related_objects_cache.php index b19fd60cc0a..e845b64add5 100644 --- a/calendar/classes/external/events_related_objects_cache.php +++ b/calendar/classes/external/events_related_objects_cache.php @@ -54,16 +54,21 @@ class events_related_objects_cache { protected $courses = null; /** - * @var array $events The related groups. + * @var array $groups The related groups. */ protected $groups = null; /** - * @var array $events The related course modules. + * @var array $coursemodules The related course modules. */ protected $coursemodules = []; /** + * @var array $moduleinstances The related module instances. + */ + protected $moduleinstances = null; + + /** * Constructor. * * @param array $events Array of event_interface events @@ -171,6 +176,33 @@ class events_related_objects_cache { } /** + * Get the related module instance for a given event. + * + * @param event_interface $event The event object. + * @return stdClass|null + */ + public function get_module_instance(event_interface $event) { + if (!$event->get_course_module()) { + return null; + } + + if (is_null($this->moduleinstances)) { + $this->load_module_instances(); + } + + $id = $event->get_course_module()->get('instance'); + $name = $event->get_course_module()->get('modname'); + + if (isset($this->moduleinstances[$name])) { + if (isset($this->moduleinstances[$name][$id])) { + return $this->moduleinstances[$name][$id]; + } + } + + return null; + } + + /** * Load the list of all of the distinct courses required for the * list of provided events and save the result in memory. */ @@ -221,4 +253,35 @@ class events_related_objects_cache { $this->groups = $DB->get_records_sql($sql, $params); } + + /** + * Load the list of all of the distinct module instances required for the + * list of provided events and save the result in memory. + */ + protected function load_module_instances() { + global $DB; + + $this->moduleinstances = []; + $modulestoload = []; + foreach ($this->events as $event) { + if ($module = $event->get_course_module()) { + $id = $module->get('instance'); + $name = $module->get('modname'); + + $ids = isset($modulestoload[$name]) ? $modulestoload[$name] : []; + $ids[$id] = true; + $modulestoload[$name] = $ids; + } + } + + if (empty($modulestoload)) { + return; + } + + foreach ($modulestoload as $modulename => $ids) { + list($idsql, $params) = $DB->get_in_or_equal(array_keys($ids)); + $sql = "SELECT * FROM {" . $modulename . "} WHERE id {$idsql}"; + $this->moduleinstances[$modulename] = $DB->get_records_sql($sql, $params); + } + } } diff --git a/calendar/classes/external/week_day_exporter.php b/calendar/classes/external/week_day_exporter.php index 951b84e3534..49980d502c5 100644 --- a/calendar/classes/external/week_day_exporter.php +++ b/calendar/classes/external/week_day_exporter.php @@ -117,9 +117,11 @@ class week_day_exporter extends day_exporter { $eventexporters = array_map(function($event) use ($cache, $output, $url) { $context = $cache->get_context($event); $course = $cache->get_course($event); + $moduleinstance = $cache->get_module_instance($event); $exporter = new calendar_event_exporter($event, [ 'context' => $context, 'course' => $course, + 'moduleinstance' => $moduleinstance, 'daylink' => $url, 'type' => $this->related['type'], 'today' => $this->data[0], diff --git a/calendar/tests/events_related_objects_cache_test.php b/calendar/tests/events_related_objects_cache_test.php new file mode 100644 index 00000000000..f0799db5347 --- /dev/null +++ b/calendar/tests/events_related_objects_cache_test.php @@ -0,0 +1,140 @@ +. + +/** + * Tests for the events_related_objects_cache. + * + * @package core_calendar + * @copyright 2017 Ryan Wyllie + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +require_once(__DIR__ . '/helpers.php'); + +use \core_calendar\external\events_related_objects_cache; +use \core_calendar\local\event\container; + +/** + * Tests for the events_related_objects_cache. + * + * @package core_calendar + * @copyright 2017 Ryan Wyllie + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class core_calendar_events_related_objects_cache_testcase extends advanced_testcase { + + /** + * Tests set up + */ + protected function setUp() { + $this->resetAfterTest(); + } + + /** + * An event with no module should return null when trying to retrieve + * the module instance. + */ + public function test_get_module_instance_no_module() { + $this->setAdminUser(); + $mapper = container::get_event_mapper(); + $legacyevent = create_event([ + 'modulename' => '', + 'instance' => 0 + ]); + $event = $mapper->from_legacy_event_to_event($legacyevent); + $cache = new events_related_objects_cache([$event]); + + $this->assertNull($cache->get_module_instance($event)); + } + + /** + * The get_module_instance should return the correct module instances + * for the given set of events in the cache. + */ + public function test_get_module_instance_with_modules() { + $this->setAdminUser(); + $mapper = container::get_event_mapper(); + $generator = $this->getDataGenerator(); + $course = $generator->create_course(); + $plugingenerator = $generator->get_plugin_generator('mod_assign'); + $instance1 = $plugingenerator->create_instance(['course' => $course->id]); + $instance2 = $plugingenerator->create_instance(['course' => $course->id]); + unset($instance1->cmid); + unset($instance2->cmid); + + $params = [ + 'type' => CALENDAR_EVENT_TYPE_ACTION, + 'courseid' => $course->id, + 'modulename' => 'assign', + 'userid' => 0, + 'eventtype' => 'due', + 'repeats' => 0, + 'timestart' => 1, + ]; + + $legacyevent1 = create_event(array_merge($params, ['name' => 'Event 1', 'instance' => $instance1->id])); + $legacyevent2 = create_event(array_merge($params, ['name' => 'Event 2', 'instance' => $instance1->id])); + $legacyevent3 = create_event(array_merge($params, ['name' => 'Event 3', 'instance' => $instance2->id])); + $event1 = $mapper->from_legacy_event_to_event($legacyevent1); + $event2 = $mapper->from_legacy_event_to_event($legacyevent2); + $event3 = $mapper->from_legacy_event_to_event($legacyevent3); + $cache = new events_related_objects_cache([$event1, $event2, $event3]); + + $eventinstance1 = $cache->get_module_instance($event1); + $eventinstance2 = $cache->get_module_instance($event2); + $eventinstance3 = $cache->get_module_instance($event3); + + $this->assertEquals($instance1, $eventinstance1); + $this->assertEquals($instance1, $eventinstance2); + $this->assertEquals($instance2, $eventinstance3); + } + + /** + * Trying to load the course module of an event that isn't in + * the cache should return null. + */ + public function test_module_instance_unknown_event() { + $this->setAdminUser(); + $mapper = container::get_event_mapper(); + $generator = $this->getDataGenerator(); + $course = $generator->create_course(); + $plugingenerator = $generator->get_plugin_generator('mod_assign'); + $instance1 = $plugingenerator->create_instance(['course' => $course->id]); + $instance2 = $plugingenerator->create_instance(['course' => $course->id]); + unset($instance1->cmid); + unset($instance2->cmid); + + $params = [ + 'type' => CALENDAR_EVENT_TYPE_ACTION, + 'courseid' => $course->id, + 'modulename' => 'assign', + 'userid' => 0, + 'eventtype' => 'due', + 'repeats' => 0, + 'timestart' => 1, + ]; + + $legacyevent1 = create_event(array_merge($params, ['name' => 'Event 1', 'instance' => $instance1->id])); + $legacyevent2 = create_event(array_merge($params, ['name' => 'Event 2', 'instance' => $instance2->id])); + $event1 = $mapper->from_legacy_event_to_event($legacyevent1); + $event2 = $mapper->from_legacy_event_to_event($legacyevent2); + $cache = new events_related_objects_cache([$event1]); + + $this->assertNull($cache->get_module_instance($event2)); + } +} -- 2.11.4.GIT