Browse Source

Implement TTL parameters for cache engines

Use the TTL parameter when setting keys to the cache. The PSR16 specs
require supporting DateInterval which is why we know support it.
Mark Story 7 years ago
parent
commit
0110ea823e

+ 23 - 0
src/Cache/CacheEngine.php

@@ -16,6 +16,7 @@ declare(strict_types=1);
 namespace Cake\Cache;
 
 use Cake\Core\InstanceConfigTrait;
+use DateInterval;
 use Psr\SimpleCache\CacheInterface;
 
 /**
@@ -350,4 +351,26 @@ abstract class CacheEngine implements CacheInterface, CacheEngineInterface
 
         triggerWarning($message);
     }
+
+    /**
+     * Convert the various expressions of a TTL value into duration in seconds
+     *
+     * @param null|int|\DateInterval $ttl The TTL value of this item. If null is sent, the
+     *   driver's default duration will be used.
+     * @return int
+     */
+    protected function duration($ttl): int
+    {
+        if ($ttl === null) {
+            return $this->_config['duration'];
+        }
+        if (is_int($ttl)) {
+            return $ttl;
+        }
+        if ($ttl instanceof DateInterval) {
+            return (int)$ttl->format('%s');
+        }
+
+        throw new InvalidArgumentException('TTL values must be one of null, int, \DateInterval');
+    }
 }

+ 1 - 1
src/Cache/Engine/ApcuEngine.php

@@ -62,7 +62,7 @@ class ApcuEngine extends CacheEngine
     public function set($key, $value, $ttl = null)
     {
         $key = $this->_key($key);
-        $duration = $this->_config['duration'];
+        $duration = $this->duration($ttl);
 
         return apcu_store($key, $value, $duration);
     }

+ 1 - 2
src/Cache/Engine/FileEngine.php

@@ -140,8 +140,7 @@ class FileEngine extends CacheEngine
             }
         }
 
-        $duration = $this->_config['duration'];
-        $expires = time() + $duration;
+        $expires = time() + $this->duration($ttl);
         $contents = implode([$expires, $lineBreak, $data, $lineBreak]);
 
         if ($this->_config['lock']) {

+ 6 - 2
src/Cache/Engine/MemcachedEngine.php

@@ -290,7 +290,7 @@ class MemcachedEngine extends CacheEngine
      */
     public function set($key, $value, $ttl = null)
     {
-        $duration = $this->_config['duration'];
+        $duration = $this->duration($ttl);
         if ($duration > 30 * DAY) {
             $duration = 0;
         }
@@ -313,8 +313,12 @@ class MemcachedEngine extends CacheEngine
         foreach ($data as $key => $value) {
             $cacheData[$this->_key($key)] = $value;
         }
+        $duration = $this->duration($ttl);
+        if ($duration > 30 * DAY) {
+            $duration = 0;
+        }
 
-        return (bool)$this->_Memcached->setMulti($cacheData);
+        return (bool)$this->_Memcached->setMulti($cacheData, $duration);
     }
 
     /**

+ 1 - 1
src/Cache/Engine/RedisEngine.php

@@ -140,7 +140,7 @@ class RedisEngine extends CacheEngine
             $value = serialize($value);
         }
 
-        $duration = $this->_config['duration'];
+        $duration = $this->duration($ttl);
         if ($duration === 0) {
             return $this->_Redis->set($key, $value);
         }

+ 1 - 1
src/Cache/Engine/WincacheEngine.php

@@ -64,7 +64,7 @@ class WincacheEngine extends CacheEngine
     public function set($key, $value, $ttl = null)
     {
         $key = $this->_key($key);
-        $duration = $this->_config['duration'];
+        $duration = $this->duration($ttl);
 
         return wincache_ucache_set($key, $value, $duration);
     }

+ 23 - 0
tests/TestCase/Cache/Engine/ApcuEngineTest.php

@@ -18,6 +18,7 @@ namespace Cake\Test\TestCase\Cache\Engine;
 
 use Cake\Cache\Cache;
 use Cake\TestSuite\TestCase;
+use DateInterval;
 
 /**
  * ApcuEngineTest class
@@ -181,6 +182,28 @@ class ApcuEngineTest extends TestCase
     }
 
     /**
+     * test set ttl parameter
+     *
+     * @return void
+     */
+    public function testSetWithTtl()
+    {
+        $this->_configCache(['duration' => 99]);
+        $engine = Cache::pool('apcu');
+        $this->assertNull($engine->get('test'));
+
+        $data = 'this is a test of the emergency broadcasting system';
+        $this->assertTrue($engine->set('default_ttl', $data));
+        $this->assertTrue($engine->set('int_ttl', $data, 1));
+        $this->assertTrue($engine->set('interval_ttl', $data, new DateInterval('PT1S')));
+
+        sleep(2);
+        $this->assertNull($engine->get('int_ttl'));
+        $this->assertNull($engine->get('interval_ttl'));
+        $this->assertSame($data, $engine->get('default_ttl'));
+    }
+
+    /**
      * testDeleteCache method
      *
      * @return void

+ 23 - 0
tests/TestCase/Cache/Engine/FileEngineTest.php

@@ -20,6 +20,7 @@ use Cake\Cache\Engine\FileEngine;
 use Cake\Cache\InvalidArgumentException;
 use Cake\Core\Configure;
 use Cake\TestSuite\TestCase;
+use DateInterval;
 
 /**
  * FileEngineTest class
@@ -173,6 +174,28 @@ class FileEngineTest extends TestCase
     }
 
     /**
+     * test set ttl parameter
+     *
+     * @return void
+     */
+    public function testSetWithTtl()
+    {
+        $this->_configCache(['duration' => 99]);
+        $engine = Cache::pool('file_test');
+        $this->assertNull($engine->get('test'));
+
+        $data = 'this is a test of the emergency broadcasting system';
+        $this->assertTrue($engine->set('default_ttl', $data));
+        $this->assertTrue($engine->set('int_ttl', $data, 1));
+        $this->assertTrue($engine->set('interval_ttl', $data, new DateInterval('PT1S')));
+
+        sleep(2);
+        $this->assertNull($engine->get('int_ttl'));
+        $this->assertNull($engine->get('interval_ttl'));
+        $this->assertSame($data, $engine->get('default_ttl'));
+    }
+
+    /**
      * testDeleteCache method
      *
      * @return void

+ 23 - 0
tests/TestCase/Cache/Engine/MemcachedEngineTest.php

@@ -18,6 +18,7 @@ namespace Cake\Test\TestCase\Cache\Engine;
 use Cake\Cache\Cache;
 use Cake\Cache\Engine\MemcachedEngine;
 use Cake\TestSuite\TestCase;
+use DateInterval;
 use Memcached;
 
 /**
@@ -587,6 +588,28 @@ class MemcachedEngineTest extends TestCase
     }
 
     /**
+     * test set ttl parameter
+     *
+     * @return void
+     */
+    public function testSetWithTtl()
+    {
+        $this->_configCache(['duration' => 99]);
+        $engine = Cache::pool('memcached');
+        $this->assertNull($engine->get('test'));
+
+        $data = 'this is a test of the emergency broadcasting system';
+        $this->assertTrue($engine->set('default_ttl', $data));
+        $this->assertTrue($engine->set('int_ttl', $data, 1));
+        $this->assertTrue($engine->set('interval_ttl', $data, new DateInterval('PT1S')));
+
+        sleep(2);
+        $this->assertNull($engine->get('int_ttl'));
+        $this->assertNull($engine->get('interval_ttl'));
+        $this->assertSame($data, $engine->get('default_ttl'));
+    }
+
+    /**
      * testDeleteCache method
      *
      * @return void

+ 23 - 0
tests/TestCase/Cache/Engine/RedisEngineTest.php

@@ -18,6 +18,7 @@ namespace Cake\Test\TestCase\Cache\Engine;
 use Cake\Cache\Cache;
 use Cake\Cache\Engine\RedisEngine;
 use Cake\TestSuite\TestCase;
+use DateInterval;
 
 /**
  * RedisEngineTest class
@@ -295,6 +296,28 @@ class RedisEngineTest extends TestCase
     }
 
     /**
+     * test set ttl parameter
+     *
+     * @return void
+     */
+    public function testSetWithTtl()
+    {
+        $this->_configCache(['duration' => 99]);
+        $engine = Cache::pool('redis');
+        $this->assertNull($engine->get('test'));
+
+        $data = 'this is a test of the emergency broadcasting system';
+        $this->assertTrue($engine->set('default_ttl', $data));
+        $this->assertTrue($engine->set('int_ttl', $data, 1));
+        $this->assertTrue($engine->set('interval_ttl', $data, new DateInterval('PT1S')));
+
+        sleep(2);
+        $this->assertNull($engine->get('int_ttl'));
+        $this->assertNull($engine->get('interval_ttl'));
+        $this->assertSame($data, $engine->get('default_ttl'));
+    }
+
+    /**
      * testDeleteCache method
      *
      * @return void

+ 22 - 0
tests/TestCase/Cache/Engine/WincacheEngineTest.php

@@ -136,6 +136,28 @@ class WincacheEngineTest extends TestCase
     }
 
     /**
+     * test set ttl parameter
+     *
+     * @return void
+     */
+    public function testSetWithTtl()
+    {
+        $this->_configCache(['duration' => 99]);
+        $engine = Cache::pool('wincache');
+        $this->assertNull($engine->get('test'));
+
+        $data = 'this is a test of the emergency broadcasting system';
+        $this->assertTrue($engine->set('default_ttl', $data));
+        $this->assertTrue($engine->set('int_ttl', $data, 1));
+        $this->assertTrue($engine->set('interval_ttl', $data, new DateInterval('PT1S')));
+
+        sleep(2);
+        $this->assertNull($engine->get('int_ttl'));
+        $this->assertNull($engine->get('interval_ttl'));
+        $this->assertSame($data, $engine->get('default_ttl'));
+    }
+
+    /**
      * testDeleteCache method
      *
      * @return void