From 1eecb821ac41d0ca5c8173ae4c64d091107fe071 Mon Sep 17 00:00:00 2001 From: Mark Johnson Date: Thu, 21 Aug 2025 13:46:56 +0100 Subject: [PATCH] MDL-86397 calendar: Filter user courses In the calendar API, `raw_event_retrieval_strategy` accepts a list of courses to return events for. If one or more users are also specified, it will find the courses the are enrolled in, then call `calendar_set_filters()` to return a sorted list of those courses, and any groups within those courses that they can see events for. The list of courses in then filtered to those passed to `raw_event_retrieval_strategy`. If the user is enrolled on lots of courses, but is only viewing the caledar for one course, this results in a lot of redundant work to fetch group data for their courses which is then not used. This either involves a lot of extra complex queries, or results in an unncessary cache hit for each course. This change re-orders the code so that the list of enrolled courses is filtered to just those courses being viewed, before it is passed to `calendar_set_filters()`. This means we are only fetching group data for those courses we will be showing events for. --- .../raw_event_retrieval_strategy.php | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/public/calendar/classes/local/event/strategies/raw_event_retrieval_strategy.php b/public/calendar/classes/local/event/strategies/raw_event_retrieval_strategy.php index 3c3ad7cf54b..0ad1c4b8200 100644 --- a/public/calendar/classes/local/event/strategies/raw_event_retrieval_strategy.php +++ b/public/calendar/classes/local/event/strategies/raw_event_retrieval_strategy.php @@ -187,6 +187,16 @@ class raw_event_retrieval_strategy implements raw_event_retrieval_strategy_inter $subqueryparams = []; $allusercourses = []; + $groupcourses = []; + if (is_array($groups) && !empty($groups)) { + $groupcourses = $DB->get_fieldset_sql( + "SELECT DISTINCT courseid + FROM {groups} + WHERE id $insqlgroups", + $inparamsgroups, + ); + } + if (is_array($users) && !empty($users)) { $userrecords = $DB->get_records_sql("SELECT * FROM {user} WHERE id $insqlusers", $inparamsusers); foreach ($userrecords as $userrecord) { @@ -194,13 +204,14 @@ class raw_event_retrieval_strategy implements raw_event_retrieval_strategy_inter $usercourses = calendar_get_default_courses(null, 'id, category, groupmode, groupmodeforce', false, $userrecord->id); - // Set calendar filters. - list($usercourses, $usergroups, $user) = calendar_set_filters($usercourses, true, $userrecord); + $filteredcourses = array_merge( + is_array($courses) ? $courses : [$courses], + $groupcourses, // Include courses for any groups we've specified. + ); + $filteredcourses = array_filter($usercourses, fn($course) => in_array($course->id, $filteredcourses)); - $filteredcourses = is_array($courses) ? $courses : [$courses]; - $filteredcourses = array_filter($usercourses, function($course) use ($filteredcourses) { - return in_array($course, $filteredcourses); - }); + // Set calendar filters. + [$filteredcourses, $usergroups, $user] = calendar_set_filters($filteredcourses, true, $userrecord); $allusercourses = array_merge($allusercourses, $filteredcourses); @@ -215,7 +226,7 @@ class raw_event_retrieval_strategy implements raw_event_retrieval_strategy_inter $subqueryconditions[] = $condition; $subqueryparams = array_merge($subqueryparams, $inuserparams); - foreach ($usercourses as $courseid) { + foreach ($filteredcourses as $courseid) { if (has_capability('moodle/site:accessallgroups', \context_course::instance($courseid), $userrecord)) { $usergroupmembership = groups_get_all_groups($courseid, $user, 0, 'g.id'); if (count($usergroupmembership) == 0) {