257 lines
6.5 KiB
PHP
257 lines
6.5 KiB
PHP
<?php
|
|
|
|
namespace Illuminate\Cache;
|
|
|
|
use Closure;
|
|
use Exception;
|
|
use Illuminate\Contracts\Cache\Store;
|
|
use Illuminate\Support\InteractsWithTime;
|
|
use Illuminate\Database\ConnectionInterface;
|
|
|
|
class DatabaseStore implements Store
|
|
{
|
|
use InteractsWithTime, RetrievesMultipleKeys;
|
|
|
|
/**
|
|
* The database connection instance.
|
|
*
|
|
* @var \Illuminate\Database\ConnectionInterface
|
|
*/
|
|
protected $connection;
|
|
|
|
/**
|
|
* The name of the cache table.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $table;
|
|
|
|
/**
|
|
* A string that should be prepended to keys.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $prefix;
|
|
|
|
/**
|
|
* Create a new database store.
|
|
*
|
|
* @param \Illuminate\Database\ConnectionInterface $connection
|
|
* @param string $table
|
|
* @param string $prefix
|
|
* @return void
|
|
*/
|
|
public function __construct(ConnectionInterface $connection, $table, $prefix = '')
|
|
{
|
|
$this->table = $table;
|
|
$this->prefix = $prefix;
|
|
$this->connection = $connection;
|
|
}
|
|
|
|
/**
|
|
* Retrieve an item from the cache by key.
|
|
*
|
|
* @param string|array $key
|
|
* @return mixed
|
|
*/
|
|
public function get($key)
|
|
{
|
|
$prefixed = $this->prefix.$key;
|
|
|
|
$cache = $this->table()->where('key', '=', $prefixed)->first();
|
|
|
|
// If we have a cache record we will check the expiration time against current
|
|
// time on the system and see if the record has expired. If it has, we will
|
|
// remove the records from the database table so it isn't returned again.
|
|
if (is_null($cache)) {
|
|
return;
|
|
}
|
|
|
|
$cache = is_array($cache) ? (object) $cache : $cache;
|
|
|
|
// If this cache expiration date is past the current time, we will remove this
|
|
// item from the cache. Then we will return a null value since the cache is
|
|
// expired. We will use "Carbon" to make this comparison with the column.
|
|
if ($this->currentTime() >= $cache->expiration) {
|
|
$this->forget($key);
|
|
|
|
return;
|
|
}
|
|
|
|
return unserialize($cache->value);
|
|
}
|
|
|
|
/**
|
|
* Store an item in the cache for a given number of minutes.
|
|
*
|
|
* @param string $key
|
|
* @param mixed $value
|
|
* @param float|int $minutes
|
|
* @return void
|
|
*/
|
|
public function put($key, $value, $minutes)
|
|
{
|
|
$key = $this->prefix.$key;
|
|
|
|
$value = serialize($value);
|
|
|
|
$expiration = $this->getTime() + (int) ($minutes * 60);
|
|
|
|
try {
|
|
$this->table()->insert(compact('key', 'value', 'expiration'));
|
|
} catch (Exception $e) {
|
|
$this->table()->where('key', $key)->update(compact('value', 'expiration'));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Increment the value of an item in the cache.
|
|
*
|
|
* @param string $key
|
|
* @param mixed $value
|
|
* @return int|bool
|
|
*/
|
|
public function increment($key, $value = 1)
|
|
{
|
|
return $this->incrementOrDecrement($key, $value, function ($current, $value) {
|
|
return $current + $value;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Decrement the value of an item in the cache.
|
|
*
|
|
* @param string $key
|
|
* @param mixed $value
|
|
* @return int|bool
|
|
*/
|
|
public function decrement($key, $value = 1)
|
|
{
|
|
return $this->incrementOrDecrement($key, $value, function ($current, $value) {
|
|
return $current - $value;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Increment or decrement an item in the cache.
|
|
*
|
|
* @param string $key
|
|
* @param mixed $value
|
|
* @param \Closure $callback
|
|
* @return int|bool
|
|
*/
|
|
protected function incrementOrDecrement($key, $value, Closure $callback)
|
|
{
|
|
return $this->connection->transaction(function () use ($key, $value, $callback) {
|
|
$prefixed = $this->prefix.$key;
|
|
|
|
$cache = $this->table()->where('key', $prefixed)
|
|
->lockForUpdate()->first();
|
|
|
|
// If there is no value in the cache, we will return false here. Otherwise the
|
|
// value will be decrypted and we will proceed with this function to either
|
|
// increment or decrement this value based on the given action callbacks.
|
|
if (is_null($cache)) {
|
|
return false;
|
|
}
|
|
|
|
$cache = is_array($cache) ? (object) $cache : $cache;
|
|
|
|
$current = unserialize($cache->value);
|
|
|
|
// Here we'll call this callback function that was given to the function which
|
|
// is used to either increment or decrement the function. We use a callback
|
|
// so we do not have to recreate all this logic in each of the functions.
|
|
$new = $callback((int) $current, $value);
|
|
|
|
if (! is_numeric($current)) {
|
|
return false;
|
|
}
|
|
|
|
// Here we will update the values in the table. We will also encrypt the value
|
|
// since database cache values are encrypted by default with secure storage
|
|
// that can't be easily read. We will return the new value after storing.
|
|
$this->table()->where('key', $prefixed)->update([
|
|
'value' => serialize($new),
|
|
]);
|
|
|
|
return $new;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get the current system time.
|
|
*
|
|
* @return int
|
|
*/
|
|
protected function getTime()
|
|
{
|
|
return $this->currentTime();
|
|
}
|
|
|
|
/**
|
|
* Store an item in the cache indefinitely.
|
|
*
|
|
* @param string $key
|
|
* @param mixed $value
|
|
* @return void
|
|
*/
|
|
public function forever($key, $value)
|
|
{
|
|
$this->put($key, $value, 5256000);
|
|
}
|
|
|
|
/**
|
|
* Remove an item from the cache.
|
|
*
|
|
* @param string $key
|
|
* @return bool
|
|
*/
|
|
public function forget($key)
|
|
{
|
|
$this->table()->where('key', '=', $this->prefix.$key)->delete();
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Remove all items from the cache.
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function flush()
|
|
{
|
|
return (bool) $this->table()->delete();
|
|
}
|
|
|
|
/**
|
|
* Get a query builder for the cache table.
|
|
*
|
|
* @return \Illuminate\Database\Query\Builder
|
|
*/
|
|
protected function table()
|
|
{
|
|
return $this->connection->table($this->table);
|
|
}
|
|
|
|
/**
|
|
* Get the underlying database connection.
|
|
*
|
|
* @return \Illuminate\Database\ConnectionInterface
|
|
*/
|
|
public function getConnection()
|
|
{
|
|
return $this->connection;
|
|
}
|
|
|
|
/**
|
|
* Get the cache key prefix.
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getPrefix()
|
|
{
|
|
return $this->prefix;
|
|
}
|
|
}
|