Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(dev/core#174) Full PSR-16 compliance for ArrayCache, Redis #12378

Merged
merged 2 commits into from
Jun 30, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 27 additions & 5 deletions CRM/Utils/Cache/ArrayCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,15 @@ class CRM_Utils_Cache_Arraycache implements CRM_Utils_Cache_Interface {
use CRM_Utils_Cache_NaiveMultipleTrait;
use CRM_Utils_Cache_NaiveHasTrait; // TODO Native implementation

const DEFAULT_TIMEOUT = 3600;

/**
* The cache storage container, an in memory array by default
*/
protected $_cache;

protected $_expires;

/**
* Constructor.
*
Expand All @@ -54,19 +58,20 @@ class CRM_Utils_Cache_Arraycache implements CRM_Utils_Cache_Interface {
*/
public function __construct($config) {
$this->_cache = array();
$this->_expires = array();
}

/**
* @param string $key
* @param mixed $value
* @param null|int|\DateInterval $ttl
* @return bool
* @throws \Psr\SimpleCache\InvalidArgumentException
*/
public function set($key, $value, $ttl = NULL) {
if ($ttl !== NULL) {
throw new \RuntimeException("FIXME: " . __CLASS__ . "::set() should support non-NULL TTL");
}
$this->_cache[$key] = $value;
CRM_Utils_Cache::assertValidKey($key);
$this->_cache[$key] = $this->reobjectify($value);
$this->_expires[$key] = CRM_Utils_Date::convertCacheTtlToExpires($ttl, self::DEFAULT_TIMEOUT);
return TRUE;
}

Expand All @@ -75,22 +80,35 @@ public function set($key, $value, $ttl = NULL) {
* @param mixed $default
*
* @return mixed
* @throws \Psr\SimpleCache\InvalidArgumentException
*/
public function get($key, $default = NULL) {
return CRM_Utils_Array::value($key, $this->_cache, $default);
CRM_Utils_Cache::assertValidKey($key);
if (isset($this->_expires[$key]) && is_numeric($this->_expires[$key]) && $this->_expires[$key] <= time()) {
return $default;
}
if (array_key_exists($key, $this->_cache)) {
return $this->reobjectify($this->_cache[$key]);
}
return $default;
}

/**
* @param string $key
* @return bool
* @throws \Psr\SimpleCache\InvalidArgumentException
*/
public function delete($key) {
CRM_Utils_Cache::assertValidKey($key);

unset($this->_cache[$key]);
unset($this->_expires[$key]);
return TRUE;
}

public function flush() {
unset($this->_cache);
unset($this->_expires);
$this->_cache = array();
return TRUE;
}
Expand All @@ -99,4 +117,8 @@ public function clear() {
return $this->flush();
}

private function reobjectify($value) {
return is_object($value) ? unserialize(serialize($value)) : $value;
}

}
14 changes: 9 additions & 5 deletions CRM/Utils/Cache/Redis.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,16 +123,18 @@ public function __construct($config) {
* @throws Exception
*/
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 (!$this->_cache->set($this->_prefix . $key, serialize($value), $this->_timeout)) {
$ttl = CRM_Utils_Date::convertCacheTtl($ttl, self::DEFAULT_TIMEOUT);
if (!$this->_cache->setex($this->_prefix . $key, $ttl, serialize($value))) {
if (PHP_SAPI === 'cli' || (Civi\Core\Container::isContainerBooted() && CRM_Core_Permission::check('view debug output'))) {
CRM_Core_Error::fatal("Redis set ($key) failed: " . $this->_cache->getLastError());
throw new CRM_Utils_Cache_CacheException("Redis set ($key) failed: " . $this->_cache->getLastError());
}
else {
Civi::log()->error("Redis set ($key) failed: " . $this->_cache->getLastError());
CRM_Core_Error::fatal("Redis set ($key) failed");
throw new CRM_Utils_Cache_CacheException("Redis set ($key) failed");
}
return FALSE;
}
Expand All @@ -146,6 +148,7 @@ public function set($key, $value, $ttl = NULL) {
* @return mixed
*/
public function get($key, $default = NULL) {
CRM_Utils_Cache::assertValidKey($key);
$result = $this->_cache->get($this->_prefix . $key);
return ($result === FALSE) ? $default : unserialize($result);
}
Expand All @@ -156,6 +159,7 @@ public function get($key, $default = NULL) {
* @return bool
*/
public function delete($key) {
CRM_Utils_Cache::assertValidKey($key);
$this->_cache->delete($this->_prefix . $key);
return TRUE;
}
Expand Down
41 changes: 41 additions & 0 deletions tests/phpunit/E2E/Cache/ArrayCacheTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 5 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2018 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License along with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/

/**
* Verify that CRM_Utils_Cache_ArrayCache complies with PSR-16.
*
* @group e2e
*/
class E2E_Cache_ArrayCacheTest extends E2E_Cache_CacheTestCase {

public function createSimpleCache() {
return CRM_Utils_Cache::create([
'name' => 'e2e arraycache test',
'type' => ['ArrayCache'],
]);
}

}
48 changes: 48 additions & 0 deletions tests/phpunit/E2E/Cache/ConfiguredMemoryTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 5 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2018 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License along with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/

/**
* Verify that CRM_Utils_Cache_{Redis,Memcache} complies with PSR-16.
*
* NOTE: Only works if the local system is configured to use one of
* those services.
*
* @group e2e
*/
class E2E_Cache_ConfiguredMemoryTest extends E2E_Cache_CacheTestCase {

public function createSimpleCache() {
$cache = Civi::cache('default');

if ($cache instanceof CRM_Utils_Cache_Redis || $cache instanceof CRM_Utils_Cache_Memcache || $cache instanceof CRM_Utils_Cache_Memcached) {
return $cache;
}
else {
$this->markTestSkipped('This environment is not configured to use a memory-backed cache service.');
}
}

}