Overview
--------
Suppose you have a clean codebase with no DAO files, and you try to run `xml/GenCode.php`.
This currently crashes.
The problem is not symptomatic day-to-day because we commit DAOs, so it's
very rare to run a full/clean initialization. However, it does get in the
way of stress-testing the correctness of GenCode.
Before
------
Since
76e697a9d750d568d0d12c10dd8173f656e8bb1e, I believe we've had a dependency-loop
in the clean-gencode scenario, which works as follows:
* We don't have any DAOs, so we run `GenCode`.
* Running `GenCode` does a partial bootstrap (i.e. `CRM_Core_Config::singleton($loadFromDB===FALSE)`)
* The partial bootstrap creates some thread-local caches (`Arraycache`)
* Before creating the cache, it normalizes the name by calling `CRM_Core_BAO_Cache::cleanKey()`
* `CRM_Core_BAO_Cache` extends `CRM_Core_DAO_Cache`
* `CRM_Core_BAO_Cache` doesn't exist - that's why we called `GenCode` at the beginning.
After
-----
This migrates the utility function `cleanKey()` to another class which is always available and
does not rely on DAOs.
$aclKeys = array_keys($acls);
$aclKeys = implode(',', $aclKeys);
- $cacheKey = CRM_Core_BAO_Cache::cleanKey("$tableName-$aclKeys");
+ $cacheKey = CRM_Utils_Cache::cleanKey("$tableName-$aclKeys");
$cache = CRM_Utils_Cache::singleton();
$ids = $cache->get($cacheKey);
if (!$ids) {
$argString = $all ? 'CRM_CT_GSE_1' : 'CRM_CT_GSE_0';
$argString .= $isSeparator ? '_1' : '_0';
$argString .= $separator;
- $argString = CRM_Core_BAO_Cache::cleanKey($argString);
+ $argString = CRM_Utils_Cache::cleanKey($argString);
if (!array_key_exists($argString, $_cache)) {
$cache = CRM_Utils_Cache::singleton();
$_cache[$argString] = $cache->get($argString);
* @return string
* Ex: '_abcd1234abcd1234' or 'ab_xx/cd_xxef'.
* A similar key, but suitable for use with PSR-16-compliant cache providers.
+ * @deprecated
+ * @see CRM_Utils_Cache::cleanKey()
*/
public static function cleanKey($key) {
- if (!is_string($key) && !is_int($key)) {
- throw new \RuntimeException("Malformed cache key");
- }
-
- $maxLen = 64;
- $escape = '-';
-
- if (strlen($key) >= $maxLen) {
- return $escape . md5($key);
- }
-
- $r = preg_replace_callback(';[^A-Za-z0-9_\.];', function($m) use ($escape) {
- return $escape . dechex(ord($m[0]));
- }, $key);
-
- return strlen($r) >= $maxLen ? $escape . md5($key) : $r;
+ return CRM_Utils_Cache::cleanKey($key);
}
}
'path' => $path,
]);
}
- return self::getGroup($group)->get(CRM_Core_BAO_Cache::cleanKey($path));
+ return self::getGroup($group)->get(CRM_Utils_Cache::cleanKey($path));
}
/**
]);
}
self::getGroup($group)
- ->set(CRM_Core_BAO_Cache::cleanKey($path), $data, self::TTL);
+ ->set(CRM_Utils_Cache::cleanKey($path), $data, self::TTL);
}
/**
// FIXME: Generate a general deprecation notice.
if ($path) {
- self::getGroup($group)->delete(CRM_Core_BAO_Cache::cleanKey($path));
+ self::getGroup($group)->delete(CRM_Utils_Cache::cleanKey($path));
}
else {
self::getGroup($group)->clear();
AND c.created_date < date_sub( NOW( ), INTERVAL %2 day )
";
$params = [
- 1 => [CRM_Core_BAO_Cache::cleanKey('CiviCRM Search PrevNextCache'), 'String'],
+ 1 => [CRM_Utils_Cache::cleanKey('CiviCRM Search PrevNextCache'), 'String'],
2 => [$cacheTimeIntervalDays, 'Integer'],
];
CRM_Core_DAO::executeQuery($sql, $params);
$key = 'id',
$force = NULL
) {
- $cacheKey = CRM_Core_BAO_Cache::cleanKey("CRM_PC_{$name}_{$all}_{$key}_{$retrieve}_{$filter}_{$condition}_{$orderby}");
+ $cacheKey = CRM_Utils_Cache::cleanKey("CRM_PC_{$name}_{$all}_{$key}_{$retrieve}_{$filter}_{$condition}_{$orderby}");
$cache = CRM_Utils_Cache::singleton();
$var = $cache->get($cacheKey);
if ($var !== NULL && empty($force)) {
$types = (array) $params['type'];
if (!empty($params['name'])) {
- $params['name'] = CRM_Core_BAO_Cache::cleanKey($params['name']);
+ $params['name'] = self::cleanKey($params['name']);
}
foreach ($types as $type) {
throw new CRM_Core_Exception("Failed to instantiate cache. No supported cache type found. " . print_r($params, 1));
}
+ /**
+ * Normalize a cache key.
+ *
+ * This bridges an impedance mismatch between our traditional caching
+ * and PSR-16 -- PSR-16 accepts a narrower range of cache keys.
+ *
+ * @param string $key
+ * Ex: 'ab/cd:ef'
+ * @return string
+ * Ex: '_abcd1234abcd1234' or 'ab_xx/cd_xxef'.
+ * A similar key, but suitable for use with PSR-16-compliant cache providers.
+ */
+ public static function cleanKey($key) {
+ if (!is_string($key) && !is_int($key)) {
+ throw new \RuntimeException("Malformed cache key");
+ }
+
+ $maxLen = 64;
+ $escape = '-';
+
+ if (strlen($key) >= $maxLen) {
+ return $escape . md5($key);
+ }
+
+ $r = preg_replace_callback(';[^A-Za-z0-9_\.];', function($m) use ($escape) {
+ return $escape . dechex(ord($m[0]));
+ }, $key);
+
+ return strlen($r) >= $maxLen ? $escape . md5($key) : $r;
+ }
+
/**
* Assert that a key is well-formed.
*
CRM_Utils_Cache::assertValidKey($key);
// If we are triggering a deletion of a prevNextCache key in the civicrm_cache tabl
// Alssure that the relevant prev_next_cache values are also removed.
- if ($this->group == CRM_Core_BAO_Cache::cleanKey('CiviCRM Search PrevNextCache')) {
+ if ($this->group == CRM_Utils_Cache::cleanKey('CiviCRM Search PrevNextCache')) {
Civi::service('prevnext')->deleteItem(NULL, $key);
}
CRM_Core_DAO::executeQuery("DELETE FROM {$this->table} WHERE {$this->where($key)}");
}
public function flush() {
- if ($this->group == CRM_Core_BAO_Cache::cleanKey('CiviCRM Search PrevNextCache') &&
+ if ($this->group == CRM_Utils_Cache::cleanKey('CiviCRM Search PrevNextCache') &&
Civi::service('prevnext') instanceof CRM_Core_PrevNextCache_Sql) {
// Use the standard PrevNextCache cleanup function here not just delete from civicrm_cache
CRM_Core_BAO_PrevNextCache::cleanupCache();
* @dataProvider getCleanKeyExamples
*/
public function testCleanKeys($inputKey, $expectKey) {
- $actualKey = CRM_Core_BAO_Cache::cleanKey($inputKey);
+ $actualKey = CRM_Utils_Cache::cleanKey($inputKey);
$this->assertEquals($expectKey, $actualKey);
}