class DrupalDatabaseCache implements DrupalCacheInterface {
protected $bin;
function __construct($bin) {
$this->bin = $bin;
}
function get($cid) {
$cids = array(
$cid,
);
$cache = $this
->getMultiple($cids);
return reset($cache);
}
function getMultiple(&$cids) {
try {
$this
->garbageCollection($this->bin);
$result = db_query('SELECT cid, data, created, expire, serialized FROM {' . db_escape_table($this->bin) . '} WHERE cid IN (:cids)', array(
':cids' => $cids,
));
$cache = array();
foreach ($result as $item) {
$item = $this
->prepareItem($item);
if ($item) {
$cache[$item->cid] = $item;
}
}
$cids = array_diff($cids, array_keys($cache));
return $cache;
} catch (Exception $e) {
return array();
}
}
protected function garbageCollection() {
$cache_lifetime = variable_get('cache_lifetime', 0);
if (isset($_SESSION['cache_expiration'])) {
$expire = REQUEST_TIME - $cache_lifetime;
foreach ($_SESSION['cache_expiration'] as $bin => $timestamp) {
if ($timestamp < $expire) {
unset($_SESSION['cache_expiration'][$bin]);
}
}
if (!$_SESSION['cache_expiration']) {
unset($_SESSION['cache_expiration']);
}
}
if (!$cache_lifetime) {
return;
}
$cache_flush = variable_get('cache_flush_' . $this->bin, 0);
if ($cache_flush && $cache_flush + $cache_lifetime <= REQUEST_TIME) {
variable_set('cache_flush_' . $this->bin, 0);
db_delete($this->bin)
->condition('expire', CACHE_PERMANENT, '<>')
->condition('expire', $cache_flush, '<=')
->execute();
}
}
protected function prepareItem($cache) {
global $user;
if (!isset($cache->data)) {
return FALSE;
}
if ($cache->expire != CACHE_PERMANENT && variable_get('cache_lifetime', 0) && isset($_SESSION['cache_expiration'][$this->bin]) && $_SESSION['cache_expiration'][$this->bin] > $cache->created) {
return FALSE;
}
if ($cache->serialized) {
$cache->data = unserialize($cache->data);
}
return $cache;
}
function set($cid, $data, $expire = CACHE_PERMANENT) {
$fields = array(
'serialized' => 0,
'created' => REQUEST_TIME,
'expire' => $expire,
);
if (!is_string($data)) {
$fields['data'] = serialize($data);
$fields['serialized'] = 1;
}
else {
$fields['data'] = $data;
$fields['serialized'] = 0;
}
try {
db_merge($this->bin)
->key(array(
'cid' => $cid,
))
->fields($fields)
->execute();
} catch (Exception $e) {
}
}
function clear($cid = NULL, $wildcard = FALSE) {
global $user;
if (empty($cid)) {
if (variable_get('cache_lifetime', 0)) {
$_SESSION['cache_expiration'][$this->bin] = REQUEST_TIME;
$cache_flush = variable_get('cache_flush_' . $this->bin, 0);
if ($cache_flush == 0) {
variable_set('cache_flush_' . $this->bin, REQUEST_TIME);
}
elseif (REQUEST_TIME > $cache_flush + variable_get('cache_lifetime', 0)) {
db_delete($this->bin)
->condition('expire', CACHE_PERMANENT, '<>')
->condition('expire', REQUEST_TIME, '<')
->execute();
variable_set('cache_flush_' . $this->bin, 0);
}
}
else {
db_delete($this->bin)
->condition('expire', CACHE_PERMANENT, '<>')
->condition('expire', REQUEST_TIME, '<')
->execute();
}
}
else {
if ($wildcard) {
if ($cid == '*') {
if ($this
->isValidBin()) {
db_truncate($this->bin)
->execute();
}
else {
throw new Exception(t('Invalid or missing cache bin specified: %bin', array(
'%bin' => $this->bin,
)));
}
}
else {
db_delete($this->bin)
->condition('cid', db_like($cid) . '%', 'LIKE')
->execute();
}
}
elseif (is_array($cid)) {
do {
db_delete($this->bin)
->condition('cid', array_splice($cid, 0, 1000), 'IN')
->execute();
} while (count($cid));
}
else {
db_delete($this->bin)
->condition('cid', $cid)
->execute();
}
}
}
function isEmpty() {
$this
->garbageCollection();
$query = db_select($this->bin);
$query
->addExpression('1');
$result = $query
->range(0, 1)
->execute()
->fetchField();
return empty($result);
}
function isValidBin() {
if ($this->bin == 'cache' || substr($this->bin, 0, 6) == 'cache_') {
return TRUE;
}
$fields = array(
'cid',
'data',
'expire',
'created',
'serialized',
);
$schema = drupal_get_schema($this->bin);
return isset($schema['fields']) && !array_diff($fields, array_keys($schema['fields']));
}
}