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.
This commit is contained in:
Mark Johnson
2025-11-12 14:39:37 +00:00
parent 41a6ad6cd2
commit 1eecb821ac
@@ -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) {