Pepote
Pepote

Reputation: 165

Laravel flush cache with more than one tag

I'm using Redis cache on Laravel 5.2, and I have my keys with 2 tags (basically), the year and the source.

Example:

$this->cache->tags(['online', 2016])->put("key1", $value1, 10));
$this->cache->tags(['online', 2016])->put("key2", $value2, 10));
$this->cache->tags(['online', 2017])->put("key3", $value3, 10));
$this->cache->tags(['online', 2017])->put("key4", $value4, 10));

$this->cache->tags(['database', 2016])->put("key5", $value5, 10));
$this->cache->tags(['database', 2016])->put("key6", $value6, 10));
$this->cache->tags(['database', 2017])->put("key7", $value7, 10));
$this->cache->tags(['database', 2017])->put("key8", $value8, 10));

I want to flush the cache for the tags 2016 & online.

Using this $this->cache->tags(['online', 2016])->flush(); It will flush everything with any of the tags, i.e., either online or 2016 (in this case key1, key2, key3, key4, key5, key6).

I want to delete everything including all the tags, i.e., both online and 2016 (in this case only key1 and key2)

Upvotes: 6

Views: 3983

Answers (3)

Joeri
Joeri

Reputation: 2308

I think I would make a key to fit the delete ...

$this->cache->tags([andKey('online', 2016)])->put("key1", $value1, 10)); 
$this->cache->tags([andKey('online', 2016)])->put("key2", $value2, 10));
    
$this->cache->tags([andKey('online', 2016)])->flush();

helper:
function andKey($a, $b)
{
   return sprintf("%s.%s", $a, $b);  
}

Bit more work, but will save loads of headache when cache system is changed.

edit: As suggested in comments you can add all keys and flush on any 3.

$this->cache->tags(['online', '2016', andKey('online', 2016)])->put("key1", $value1, 10)); 
$this->cache->tags(['online', '2016', andKey('online', 2016)])->put("key2", $value2, 10));
   
$this->cache->tags([andKey('online', 2016)])->flush();

helper:
function andKey($a, $b)
{
   return sprintf("combined.%s.%s", $a, $b);  
}

Upvotes: 2

nat_jea
nat_jea

Reputation: 323

In 'yourKeyGoesHere' you can insert a string used as same as a like with a * or insert directly the exactly key.

//Get all cached data ... 
$redis = Cache::getRedis();
$a_keys = $redis->keys("*yourKeyGoesHere*");
foreach ($a_keys as $key){
  //Your Action on key ... (Example delete / forget)
  $redis->del($key);
 }

Upvotes: 0

apokryfos
apokryfos

Reputation: 40653

So this took a bit of digging but here's the verdict.

Yes this is technically possible (the best kind of possible?)

First of all, the RedisTaggedCache (responsible for implementing tagging in redis) stores all tag member keys in a redis set. Here's how to discover where it is and how you can get all keys:

function getAllTagKeys($cache,$tags) {
    $tagStore = new TagSet($cache->getStore(),$tags);
    $key = "<prefix>:{$tagStore->getNamespace()}:". RedisTaggedCache::REFERENCE_KEY_STANDARD;//use REFERENCE_KEY_FOREVER if the keys are cached forever or both one after the other to get all of them
    return collect($cache->getRedis()->smembers($key));
}

Then you can do:

getAllTagKeys($this->cache, ["online"])
    ->insersect(getAllTagKeys($this->cache, ["2016"]))
    ->each(function ($v) {
         $this->cache->getRedis()->del();
     });

This looks like a horrible way to do this. Perhaps it's more sensible to make a feature request to Laravel since this looks like it's something they should be exposing?

Upvotes: 3

Related Questions