core/lib/Drupal/Core/Cache/Cache.php | 22 +++++++++++++++ core/lib/Drupal/Core/Menu/MenuTreeStorage.php | 10 ++----- core/modules/user/src/PermissionsHash.php | 5 +--- core/tests/Drupal/Tests/Core/Cache/CacheTest.php | 34 ++++++++++++++++++++++++ 4 files changed, 59 insertions(+), 12 deletions(-) diff --git a/core/lib/Drupal/Core/Cache/Cache.php b/core/lib/Drupal/Core/Cache/Cache.php index 4b475c3..ddf444e 100644 --- a/core/lib/Drupal/Core/Cache/Cache.php +++ b/core/lib/Drupal/Core/Cache/Cache.php @@ -72,6 +72,28 @@ public static function validateTags(array $tags) { } /** + * Build an array of cache tags from a given prefix and an array of suffixes. + * + * Each suffix will be converted to a cache tag by appending it to the prefix, + * with a colon between them. + * + * @param string $prefix + * A prefix string. + * @param array $suffixes + * An array of suffixes. Will be cast to strings. + * + * @return string[] + * An array of cache tags. + */ + public static function buildTags($prefix, array $suffixes) { + $tags = []; + foreach ($suffixes as $suffix) { + $tags[] = $prefix . ':' . $suffix; + } + return $tags; + } + + /** * Deletes items from all bins with any of the specified tags. * * Many sites have more than one active cache backend, and each backend may diff --git a/core/lib/Drupal/Core/Menu/MenuTreeStorage.php b/core/lib/Drupal/Core/Menu/MenuTreeStorage.php index b7e525f..fb75390 100644 --- a/core/lib/Drupal/Core/Menu/MenuTreeStorage.php +++ b/core/lib/Drupal/Core/Menu/MenuTreeStorage.php @@ -193,10 +193,7 @@ public function rebuild(array $definitions) { $this->resetDefinitions(); $affected_menus = $this->getMenuNames() + $before_menus; // Invalidate any cache tagged with any menu name. - $cache_tags = []; - foreach ($affected_menus as $affected_menu) { - $cache_tags[] = 'menu:' . $affected_menu; - } + $cache_tags = Cache::buildTags('menu', $affected_menus); Cache::invalidateTags($cache_tags); $this->resetDefinitions(); // Every item in the cache bin should have one of the menu cache tags but it @@ -259,10 +256,7 @@ protected function safeExecuteSelect(SelectInterface $query) { public function save(array $link) { $affected_menus = $this->doSave($link); $this->resetDefinitions(); - $cache_tags = []; - foreach ($affected_menus as $affected_menu) { - $cache_tags[] = 'menu:' . $affected_menu; - } + $cache_tags = Cache::buildTags('menu', $affected_menus); Cache::invalidateTags($cache_tags); return $affected_menus; } diff --git a/core/modules/user/src/PermissionsHash.php b/core/modules/user/src/PermissionsHash.php index 3d91576..8fffcdd 100644 --- a/core/modules/user/src/PermissionsHash.php +++ b/core/modules/user/src/PermissionsHash.php @@ -59,10 +59,7 @@ public function generate(AccountInterface $account) { } else { $permissions_hash = $this->doGenerate($sorted_roles); - $tags = []; - foreach ($sorted_roles as $role) { - $tags[] = 'user_role:' . $role; - } + $tags = Cache::buildTags('menu', $sorted_roles); $this->cache->set("user_permissions_hash:$role_list", $permissions_hash, Cache::PERMANENT, $tags); } diff --git a/core/tests/Drupal/Tests/Core/Cache/CacheTest.php b/core/tests/Drupal/Tests/Core/Cache/CacheTest.php index e000e12..e5ae63c 100644 --- a/core/tests/Drupal/Tests/Core/Cache/CacheTest.php +++ b/core/tests/Drupal/Tests/Core/Cache/CacheTest.php @@ -83,6 +83,40 @@ public function testMergeTags(array $a, array $b, array $expected) { } /** + * Provides a list of pairs of (prefix, suffixes) to build cache tags from. + * + * @return array + */ + public function buildTagsProvider() { + return [ + ['node', [1], ['node:1']], + ['node', [1, 2, 3], ['node:1', 'node:2', 'node:3']], + ['node', [3, 2, 1], ['node:3', 'node:2', 'node:1']], + ['node', [NULL], ['node:']], + ['node', [TRUE, FALSE], ['node:1', 'node:']], + ['node', ['a', 'z', 'b'], ['node:a', 'node:z', 'node:b']], + // No suffixes, no cache tags. + ['', [], []], + ['node', [], []], + // Only suffix values matter, not keys: verify that expectation. + ['node', [5 => 145, 4545 => 3], ['node:145', 'node:3']], + ['node', [5 => TRUE], ['node:1']], + ['node', [5 => NULL], ['node:']], + ['node', ['a' => NULL], ['node:']], + ['node', ['a' => TRUE], ['node:1']], + ]; + } + + /** + * @covers buildTags + * + * @dataProvider buildTagsProvider + */ + public function testBuildTags($prefix, array $suffixes, array $expected) { + $this->assertEquals($expected, Cache::buildTags($prefix, $suffixes)); + } + + /** * @covers deleteTags * * @expectedException \LogicException