From 9e1a686f3db58639b005ee78c1b63f0ed75b16cf Mon Sep 17 00:00:00 2001 From: Tim Otten Date: Tue, 26 Jun 2018 21:49:54 -0700 Subject: [PATCH] (dev/core#174) APCcache - Updates to comply with PSR-16 One noteable quirk is that APC retains expired (per TTL) records until the following page-request. To comply with the test suite, we have to double-check the expiration time. --- CRM/Utils/Cache/APCcache.php | 30 ++++++++++---- tests/phpunit/E2E/Cache/APCcacheTest.php | 53 ++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 9 deletions(-) create mode 100644 tests/phpunit/E2E/Cache/APCcacheTest.php diff --git a/CRM/Utils/Cache/APCcache.php b/CRM/Utils/Cache/APCcache.php index a8b4e5cd69..26fa86b241 100644 --- a/CRM/Utils/Cache/APCcache.php +++ b/CRM/Utils/Cache/APCcache.php @@ -81,10 +81,14 @@ class CRM_Utils_Cache_APCcache implements CRM_Utils_Cache_Interface { * @return bool */ public function set($key, $value, $ttl = NULL) { - if ($ttl !== NULL) { - throw new \RuntimeException("FIXME: " . __CLASS__ . "::set() should support non-NULL TTL"); + CRM_Utils_Cache::assertValidKey($key); + if (is_int($ttl) && $ttl <= 0) { + return $this->delete($key); } - if (!apc_store($this->_prefix . $key, $value, $this->_timeout)) { + + $ttl = CRM_Utils_Date::convertCacheTtl($ttl, $this->_timeout); + $expires = time() + $ttl; + if (!apc_store($this->_prefix . $key, ['e' => $expires, 'v' => $value], $ttl)) { return FALSE; } return TRUE; @@ -97,10 +101,12 @@ class CRM_Utils_Cache_APCcache implements CRM_Utils_Cache_Interface { * @return mixed */ public function get($key, $default = NULL) { - if ($default !== NULL) { - throw new \RuntimeException("FIXME: " . __CLASS__ . "::get() only supports NULL default"); + CRM_Utils_Cache::assertValidKey($key); + $result = apc_fetch($this->_prefix . $key, $success); + if ($success && isset($result['e']) && $result['e'] > time()) { + return $this->reobjectify($result['v']); } - return apc_fetch($this->_prefix . $key); + return $default; } /** @@ -109,20 +115,22 @@ class CRM_Utils_Cache_APCcache implements CRM_Utils_Cache_Interface { * @return bool|string[] */ public function delete($key) { - return apc_delete($this->_prefix . $key); + CRM_Utils_Cache::assertValidKey($key); + apc_delete($this->_prefix . $key); + return TRUE; } public function flush() { $allinfo = apc_cache_info('user'); $keys = $allinfo['cache_list']; - $prefix = $this->_prefix . "CRM_"; // Our keys follows this pattern: ([A-Za-z0-9_]+)?CRM_[A-Za-z0-9_]+ + $prefix = $this->_prefix; // Our keys follows this pattern: ([A-Za-z0-9_]+)?CRM_[A-Za-z0-9_]+ $lp = strlen($prefix); // Get prefix length foreach ($keys as $key) { $name = $key['info']; if ($prefix == substr($name, 0, $lp)) { // Ours? - apc_delete($this->_prefix . $name); + apc_delete($name); } } return TRUE; @@ -132,4 +140,8 @@ class CRM_Utils_Cache_APCcache implements CRM_Utils_Cache_Interface { return $this->flush(); } + private function reobjectify($value) { + return is_object($value) ? unserialize(serialize($value)) : $value; + } + } diff --git a/tests/phpunit/E2E/Cache/APCcacheTest.php b/tests/phpunit/E2E/Cache/APCcacheTest.php new file mode 100644 index 0000000000..4ab715ea14 --- /dev/null +++ b/tests/phpunit/E2E/Cache/APCcacheTest.php @@ -0,0 +1,53 @@ +markTestSkipped('This environment does not have the APC extension.'); + } + + if (PHP_SAPI === 'cli') { + $c = (string) ini_get('apc.enable_cli'); + if ($c != 1 && strtolower($c) !== 'on') { + $this->markTestSkipped('This environment is not configured to use APC cache service. Set apc.enable_cli=on'); + } + } + + $config = [ + 'prefix' => 'foozball/', + ]; + $c = new CRM_Utils_Cache_APCcache($config); + return $c; + } + +} -- 2.25.1