diff --git a/mod/forum/db/caches.php b/mod/forum/db/caches.php index ecfd9e38503..beba7334d3c 100644 --- a/mod/forum/db/caches.php +++ b/mod/forum/db/caches.php @@ -32,4 +32,13 @@ $definitions = [ 'simpledata' => true, 'staticacceleration' => true ], + 'forum_count_discussions' => [ + 'mode' => cache_store::MODE_REQUEST, + 'simplekeys' => true, + 'simpledata' => true, + 'staticacceleration' => true, + 'invalidationevents' => [ + 'changesinforumdiscussions', + ], + ], ]; diff --git a/mod/forum/lang/en/forum.php b/mod/forum/lang/en/forum.php index 9ad619d052b..67f48cd3938 100644 --- a/mod/forum/lang/en/forum.php +++ b/mod/forum/lang/en/forum.php @@ -62,6 +62,7 @@ $string['blockperiod_help'] = 'Students can be blocked from posting more than a $string['blockperioddisabled'] = 'Don\'t block'; $string['blogforum'] = 'Standard forum displayed in a blog-like format'; $string['bynameondate'] = 'by {$a->name} - {$a->date}'; +$string['cachedef_forum_count_discussions'] = 'Forum discussions count'; $string['cachedef_forum_is_tracked'] = 'Forum tracking status for user'; $string['calendardue'] = '{$a} is due'; $string['cancelreply'] = 'Cancel reply'; diff --git a/mod/forum/lib.php b/mod/forum/lib.php index aa2f1caf2ba..1593ff94377 100644 --- a/mod/forum/lib.php +++ b/mod/forum/lib.php @@ -1495,7 +1495,6 @@ function forum_count_discussion_replies($forumid, $forumsort = "", $limit = -1, * @global object * @global object * @global object - * @staticvar array $cache * @param object $forum * @param object $cm * @param object $course @@ -1504,13 +1503,21 @@ function forum_count_discussion_replies($forumid, $forumsort = "", $limit = -1, function forum_count_discussions($forum, $cm, $course) { global $CFG, $DB, $USER; - static $cache = array(); + $cache = cache::make('mod_forum', 'forum_count_discussions'); + $cachedcounts = $cache->get($course->id); + if ($cachedcounts === false) { + $cachedcounts = []; + } $now = floor(time() / 60) * 60; // DB Cache Friendly. $params = array($course->id); - if (!isset($cache[$course->id])) { + if (!isset($cachedcounts[$forum->id])) { + // Initialize the cachedcounts for this forum id to 0 by default. After the + // database query, if there are discussions then it should update the count. + $cachedcounts[$forum->id] = 0; + if (!empty($CFG->forum_enabletimedposts)) { $timedsql = "AND d.timestart < ? AND (d.timeend = 0 OR d.timeend > ?)"; $params[] = $now; @@ -1528,26 +1535,24 @@ function forum_count_discussions($forum, $cm, $course) { if ($counts = $DB->get_records_sql($sql, $params)) { foreach ($counts as $count) { - $counts[$count->id] = $count->dcount; + $cachedcounts[$count->id] = $count->dcount; } - $cache[$course->id] = $counts; - } else { - $cache[$course->id] = array(); - } - } - if (empty($cache[$course->id][$forum->id])) { - return 0; + $cache->set($course->id, $cachedcounts); + } else { + $cache->set($course->id, $cachedcounts); + return $cachedcounts[$forum->id]; + } } $groupmode = groups_get_activity_groupmode($cm, $course); if ($groupmode != SEPARATEGROUPS) { - return $cache[$course->id][$forum->id]; + return $cachedcounts[$forum->id]; } if (has_capability('moodle/site:accessallgroups', context_module::instance($cm->id))) { - return $cache[$course->id][$forum->id]; + return $cachedcounts[$forum->id]; } require_once($CFG->dirroot.'/course/lib.php'); @@ -3113,6 +3118,9 @@ function forum_add_discussion($discussion, $mform=null, $unused=null, $userid=nu forum_trigger_content_uploaded_event($post, $cm, 'forum_add_discussion'); } + // Clear the discussion count cache just in case it's in the same request. + \cache_helper::purge_by_event('changesinforumdiscussions'); + return $post->discussion; } @@ -3173,6 +3181,9 @@ function forum_delete_discussion($discussion, $fulldelete, $course, $cm, $forum) $event->add_record_snapshot('forum_discussions', $discussion); $event->trigger(); + // Clear the discussion count cache just in case it's in the same request. + \cache_helper::purge_by_event('changesinforumdiscussions'); + return $result; } diff --git a/mod/forum/tests/lib_test.php b/mod/forum/tests/lib_test.php index 4c2295e2465..2624f053abe 100644 --- a/mod/forum/tests/lib_test.php +++ b/mod/forum/tests/lib_test.php @@ -4291,4 +4291,87 @@ class lib_test extends \advanced_testcase { $this->assertIsObject($throttling); $this->assertFalse($throttling->canpost); } + + /** + * Tests forum_count_discussions. + * + * @covers ::forum_count_discussions + */ + public function test_forum_count_discussions(): void { + $this->resetAfterTest(); + + $generator = $this->getDataGenerator(); + $forumgenerator = $generator->get_plugin_generator('mod_forum'); + $course1 = $generator->create_course(); + $course2 = $generator->create_course(); + $student = $generator->create_user(['trackforums' => 1]); + + // First forum. + $forumobj1 = new \stdClass(); + $forumobj1->introformat = FORMAT_HTML; + $forumobj1->course = $course1->id; + $forumobj1->trackingtype = FORUM_TRACKING_FORCED; + $forum1 = $generator->create_module('forum', $forumobj1); + $forum1cm = get_coursemodule_from_id('forum', $forum1->cmid, 0, false, MUST_EXIST); + + // Second forum. + $forumobj2 = new \stdClass(); + $forumobj2->introformat = FORMAT_HTML; + $forumobj2->course = $course2->id; + $forumobj2->trackingtype = FORUM_TRACKING_OFF; + $forum2 = $generator->create_module('forum', $forumobj2); + $forum2cm = get_coursemodule_from_id('forum', $forum2->cmid, 0, false, MUST_EXIST); + + // Third forum. + $forumobj3 = new \stdClass(); + $forumobj3->introformat = FORMAT_HTML; + $forumobj3->course = $course2->id; + $forumobj3->trackingtype = FORUM_TRACKING_OFF; + $forum3 = $generator->create_module('forum', $forumobj3); + $forum3cm = get_coursemodule_from_id('forum', $forum3->cmid, 0, false, MUST_EXIST); + + // First make sure there are no discussions for any of the forums. + $f1discussionscount = forum_count_discussions($forum1, $forum1cm, $course1); + $this->assertEquals(0, $f1discussionscount); + $f2discussionscount = forum_count_discussions($forum2, $forum2cm, $course2); + $this->assertEquals(0, $f2discussionscount); + $f3discussionscount = forum_count_discussions($forum3, $forum3cm, $course2); + $this->assertEquals(0, $f3discussionscount); + + // Add 3 discussions to forum 1. + $discussionobj1 = new \stdClass(); + $discussionobj1->course = $course1->id; + $discussionobj1->userid = $student->id; + $discussionobj1->forum = $forum1->id; + $forumgenerator->create_discussion($discussionobj1); + $forumgenerator->create_discussion($discussionobj1); + $forumgenerator->create_discussion($discussionobj1); + + // Make sure there are 3 discussions. + $f1discussionscount = forum_count_discussions($forum1, $forum1cm, $course1); + $this->assertEquals(3, $f1discussionscount); + + // Add 4 discussions to forum 2. + $discussionobj2 = new \stdClass(); + $discussionobj2->course = $course2->id; + $discussionobj2->userid = $student->id; + $discussionobj2->forum = $forum2->id; + $forumgenerator->create_discussion($discussionobj2); + $forumgenerator->create_discussion($discussionobj2); + $forumgenerator->create_discussion($discussionobj2); + $discussion24 = $forumgenerator->create_discussion($discussionobj2); + + // Make sure there are 4 discussions. + $f2discussionscount = forum_count_discussions($forum2, $forum2cm, $course2); + $this->assertEquals(4, $f2discussionscount); + + // Delete one discussion from forum 2. + forum_delete_discussion($discussion24, true, $course2, $forum2cm, $forum2); + $f2discussionscount = forum_count_discussions($forum2, $forum2cm, $course2); + $this->assertEquals(3, $f2discussionscount); + + // Make sure there are no discussions. + $f3discussionscount = forum_count_discussions($forum3, $forum3cm, $course2); + $this->assertEquals(0, $f3discussionscount); + } } diff --git a/mod/forum/version.php b/mod/forum/version.php index 7ebbeb0d566..635fe6c4289 100644 --- a/mod/forum/version.php +++ b/mod/forum/version.php @@ -24,6 +24,6 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2023100900; // The current module version (Date: YYYYMMDDXX). +$plugin->version = 2023100901; // The current module version (Date: YYYYMMDDXX). $plugin->requires = 2023100400; // Requires this Moodle version. $plugin->component = 'mod_forum'; // Full name of the plugin (used for diagnostics)