Skip to content

Commit

Permalink
MDL-83185 core_courseformat: method to invalidate state cache
Browse files Browse the repository at this point in the history
  • Loading branch information
ferranrecio committed Oct 30, 2024
1 parent 85d70d6 commit 2da6493
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 3 deletions.
14 changes: 14 additions & 0 deletions course/format/classes/base.php
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,20 @@ public static function session_cache(stdClass $course): string {
return self::session_cache_reset($course);
}

/**
* Prune a course state cache for all open sessions.
*
* Most course edits does not require to invalidate the cache for all users
* because the cache relies on the course cacherev value. However, there are
* actions like editing the groups that do not change the course cacherev.
*
* @param \stdClass $course
* @return void
*/
public static function invalidate_all_session_caches_for_course(stdClass $course): void {
\cache_helper::invalidate_by_event('changesincoursestate', [$course->id]);
}

/**
* Returns the format name used by this course
*
Expand Down
4 changes: 2 additions & 2 deletions course/format/classes/hook_listener.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public static function add_members_to_group(
): void {
$group = $hook->groupinstance;
$course = get_course($group->courseid);
base::session_cache_reset($course);
base::invalidate_all_session_caches_for_course($course);
}

/**
Expand All @@ -50,6 +50,6 @@ public static function remove_members_from_group(
): void {
$group = $hook->groupinstance;
$course = get_course($group->courseid);
base::session_cache_reset($course);
base::invalidate_all_session_caches_for_course($course);
}
}
78 changes: 78 additions & 0 deletions course/format/tests/base_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -996,6 +996,84 @@ public function test_is_section_visible(): void {
$this->assertFalse($format->is_section_visible($modinfostudent->get_section_info(1)));
$this->assertFalse($format->is_section_visible($modinfostudent->get_section_info(2)));
}

/**
* Test can_sections_be_removed_from_navigation().
*
* @covers ::session_cache
* @covers ::session_cache_reset
* @covers ::session_cache_reset_all
* @covers ::invalidate_all_session_caches_for_course
*/
public function test_session_caches_methods(): void {
global $DB;

$this->resetAfterTest();
$generator = $this->getDataGenerator();

$course1 = $generator->create_course(['format' => 'topics']);
$course2 = $generator->create_course(['format' => 'topics']);

// Force some cacherev to the course.
$course1->cacherev = 12345;
$course2->cacherev = 67890;
$DB->set_field('course', 'cacherev', $course1->cacherev, ['id' => $course1->id]);
$DB->set_field('course', 'cacherev', $course2->cacherev, ['id' => $course2->id]);

$teacher = $generator->create_and_enrol($course1, 'editingteacher');
$generator->enrol_user($teacher->id, $course2->id, 'editingteacher');
$this->setUser($teacher);

// The cache key uses time() as hash. To not wait a second between calls we fake an initial value.
$statecache = cache::make('core', 'courseeditorstate');
$statecache->set($course1->id, $course1->cacherev . '_11111');
$statecache->set($course2->id, $course2->cacherev . '_22222');

$course1cachekey = \core_courseformat\base::session_cache($course1);

// Validate the method returns the same value when called twice.
$course1cachekeyagain = \core_courseformat\base::session_cache($course1);
$this->assertEquals($course1cachekey, $course1cachekeyagain);

// Validate other course has a diferent cache key.
$course2cachekey = \core_courseformat\base::session_cache($course2);
$this->assertNotEquals($course1cachekey, $course2cachekey);

// Reset the specific course cache.
\core_courseformat\base::session_cache_reset($course1);

$resetcachekey = \core_courseformat\base::session_cache($course1);
$this->assertNotEquals($course1cachekey, $resetcachekey);

$reset2cachekey = \core_courseformat\base::session_cache($course2);
$this->assertEquals($course2cachekey, $reset2cachekey);

// Return to the initial value.
$statecache->set($course1->id, $course1->cacherev . '_11111');
$statecache->set($course2->id, $course2->cacherev . '_22222');

// Reset all user course caches.
\core_courseformat\base::session_cache_reset_all();

$resetallcachekey = \core_courseformat\base::session_cache($course1);
$this->assertNotEquals($course1cachekey, $resetallcachekey);

$resetall2cachekey = \core_courseformat\base::session_cache($course2);
$this->assertNotEquals($course2cachekey, $resetall2cachekey);

// Return to the initial value.
$statecache->set($course1->id, $course1->cacherev . '_11111');
$statecache->set($course2->id, $course2->cacherev . '_22222');

// Invalidate cache on course 1.
\core_courseformat\base::invalidate_all_session_caches_for_course($course1);

$invalidatecachekey = \core_courseformat\base::session_cache($course1);
$this->assertNotEquals($course1cachekey, $invalidatecachekey);

$invalidate2cachekey = \core_courseformat\base::session_cache($course2);
$this->assertEquals($course2cachekey, $invalidate2cachekey);
}
}

/**
Expand Down
3 changes: 3 additions & 0 deletions lib/db/caches.php
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,9 @@
'mode' => cache_store::MODE_SESSION,
'simplekeys' => true,
'simpledata' => true,
'invalidationevents' => [
'changesincoursestate',
],
],
// Course actions instances cache.
'courseactionsinstances' => [
Expand Down
2 changes: 1 addition & 1 deletion version.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@

defined('MOODLE_INTERNAL') || die();

$version = 2024102500.00; // YYYYMMDD = weekly release date of this DEV branch.
$version = 2024102500.01; // YYYYMMDD = weekly release date of this DEV branch.
// RR = release increments - 00 in DEV branches.
// .XX = incremental changes.
$release = '5.0dev (Build: 20241025)'; // Human-friendly version name
Expand Down

0 comments on commit 2da6493

Please sign in to comment.