dependencies-upgrade

This commit is contained in:
RafficMohammed
2023-01-08 02:20:59 +05:30
parent 7870479b18
commit 49021a4497
1711 changed files with 74994 additions and 70803 deletions

View File

@@ -0,0 +1,85 @@
<?php
namespace Illuminate\Cache;
class CacheLock extends Lock
{
/**
* The cache store implementation.
*
* @var \Illuminate\Contracts\Cache\Store
*/
protected $store;
/**
* Create a new lock instance.
*
* @param \Illuminate\Contracts\Cache\Store $store
* @param string $name
* @param int $seconds
* @param string|null $owner
* @return void
*/
public function __construct($store, $name, $seconds, $owner = null)
{
parent::__construct($name, $seconds, $owner);
$this->store = $store;
}
/**
* Attempt to acquire the lock.
*
* @return bool
*/
public function acquire()
{
if (method_exists($this->store, 'add') && $this->seconds > 0) {
return $this->store->add(
$this->name, $this->owner, $this->seconds
);
}
if (! is_null($this->store->get($this->name))) {
return false;
}
return ($this->seconds > 0)
? $this->store->put($this->name, $this->owner, $this->seconds)
: $this->store->forever($this->name, $this->owner, $this->seconds);
}
/**
* Release the lock.
*
* @return bool
*/
public function release()
{
if ($this->isOwnedByCurrentProcess()) {
return $this->store->forget($this->name);
}
return false;
}
/**
* Releases this lock regardless of ownership.
*
* @return void
*/
public function forceRelease()
{
$this->store->forget($this->name);
}
/**
* Returns the owner value written into the driver for this lock.
*
* @return mixed
*/
protected function getCurrentOwner()
{
return $this->store->get($this->name);
}
}

View File

@@ -199,7 +199,11 @@ class CacheManager implements FactoryContract
$connection = $config['connection'] ?? 'default';
return $this->repository(new RedisStore($redis, $this->getPrefix($config), $connection));
$store = new RedisStore($redis, $this->getPrefix($config), $connection);
return $this->repository(
$store->setLockConnection($config['lock_connection'] ?? $connection)
);
}
/**
@@ -212,15 +216,17 @@ class CacheManager implements FactoryContract
{
$connection = $this->app['db']->connection($config['connection'] ?? null);
return $this->repository(
new DatabaseStore(
$connection,
$config['table'],
$this->getPrefix($config),
$config['lock_table'] ?? 'cache_locks',
$config['lock_lottery'] ?? [2, 100]
)
$store = new DatabaseStore(
$connection,
$config['table'],
$this->getPrefix($config),
$config['lock_table'] ?? 'cache_locks',
$config['lock_lottery'] ?? [2, 100]
);
return $this->repository($store->setLockConnection(
$this->app['db']->connection($config['lock_connection'] ?? $config['connection'] ?? null)
));
}
/**
@@ -231,21 +237,11 @@ class CacheManager implements FactoryContract
*/
protected function createDynamodbDriver(array $config)
{
$dynamoConfig = [
'region' => $config['region'],
'version' => 'latest',
'endpoint' => $config['endpoint'] ?? null,
];
if ($config['key'] && $config['secret']) {
$dynamoConfig['credentials'] = Arr::only(
$config, ['key', 'secret', 'token']
);
}
$client = $this->newDynamodbClient($config);
return $this->repository(
new DynamoDbStore(
new DynamoDbClient($dynamoConfig),
$client,
$config['table'],
$config['attributes']['key'] ?? 'key',
$config['attributes']['value'] ?? 'value',
@@ -255,6 +251,28 @@ class CacheManager implements FactoryContract
);
}
/**
* Create new DynamoDb Client instance.
*
* @return DynamoDbClient
*/
protected function newDynamodbClient(array $config)
{
$dynamoConfig = [
'region' => $config['region'],
'version' => 'latest',
'endpoint' => $config['endpoint'] ?? null,
];
if (isset($config['key']) && isset($config['secret'])) {
$dynamoConfig['credentials'] = Arr::only(
$config, ['key', 'secret', 'token']
);
}
return new DynamoDbClient($dynamoConfig);
}
/**
* Create a new cache repository with the given implementation.
*
@@ -314,7 +332,11 @@ class CacheManager implements FactoryContract
*/
protected function getConfig($name)
{
return $this->app['config']["cache.stores.{$name}"];
if (! is_null($name) && $name !== 'null') {
return $this->app['config']["cache.stores.{$name}"];
}
return ['driver' => 'null'];
}
/**
@@ -357,6 +379,19 @@ class CacheManager implements FactoryContract
return $this;
}
/**
* Disconnect the given driver and remove from local cache.
*
* @param string|null $name
* @return void
*/
public function purge($name = null)
{
$name = $name ?? $this->getDefaultDriver();
unset($this->stores[$name]);
}
/**
* Register a custom driver creator Closure.
*

View File

@@ -30,6 +30,12 @@ class CacheServiceProvider extends ServiceProvider implements DeferrableProvider
$this->app->singleton('memcached.connector', function () {
return new MemcachedConnector;
});
$this->app->singleton(RateLimiter::class, function ($app) {
return new RateLimiter($app->make('cache')->driver(
$app['config']->get('cache.limiter')
));
});
}
/**
@@ -40,7 +46,7 @@ class CacheServiceProvider extends ServiceProvider implements DeferrableProvider
public function provides()
{
return [
'cache', 'cache.store', 'cache.psr6', 'memcached.connector',
'cache', 'cache.store', 'cache.psr6', 'memcached.connector', RateLimiter::class,
];
}
}

View File

@@ -116,7 +116,7 @@ class ClearCommand extends Command
*/
protected function tags()
{
return array_filter(explode(',', $this->option('tags')));
return array_filter(explode(',', $this->option('tags') ?? ''));
}
/**

View File

@@ -14,10 +14,16 @@ class CreateCacheTable extends Migration
public function up()
{
Schema::create('cache', function (Blueprint $table) {
$table->string('key')->unique();
$table->string('key')->primary();
$table->mediumText('value');
$table->integer('expiration');
});
Schema::create('cache_locks', function (Blueprint $table) {
$table->string('key')->primary();
$table->string('owner');
$table->integer('expiration');
});
}
/**
@@ -28,5 +34,6 @@ class CreateCacheTable extends Migration
public function down()
{
Schema::dropIfExists('cache');
Schema::dropIfExists('cache_locks');
}
}

View File

@@ -136,4 +136,14 @@ class DatabaseLock extends Lock
{
return optional($this->connection->table($this->table)->where('key', $this->name)->first())->owner;
}
/**
* Get the name of the database connection being used to manage the lock.
*
* @return string
*/
public function getConnectionName()
{
return $this->connection->getName();
}
}

View File

@@ -23,6 +23,13 @@ class DatabaseStore implements LockProvider, Store
*/
protected $connection;
/**
* The database connection instance that should be used to manage locks.
*
* @var \Illuminate\Database\ConnectionInterface
*/
protected $lockConnection;
/**
* The name of the cache table.
*
@@ -155,8 +162,6 @@ class DatabaseStore implements LockProvider, Store
'expiration' => $expiration,
]) >= 1;
}
return false;
}
/**
@@ -267,7 +272,7 @@ class DatabaseStore implements LockProvider, Store
public function lock($name, $seconds = 0, $owner = null)
{
return new DatabaseLock(
$this->connection,
$this->lockConnection ?? $this->connection,
$this->lockTable,
$this->prefix.$name,
$seconds,
@@ -333,6 +338,19 @@ class DatabaseStore implements LockProvider, Store
return $this->connection;
}
/**
* Specify the name of the connection that should be used to manage locks.
*
* @param \Illuminate\Database\ConnectionInterface $connection
* @return $this
*/
public function setLockConnection($connection)
{
$this->lockConnection = $connection;
return $this;
}
/**
* Get the cache key prefix.
*

View File

@@ -34,9 +34,11 @@ class DynamoDbLock extends Lock
*/
public function acquire()
{
return $this->dynamo->add(
$this->name, $this->owner, $this->seconds
);
if ($this->seconds > 0) {
return $this->dynamo->add($this->name, $this->owner, $this->seconds);
} else {
return $this->dynamo->add($this->name, $this->owner, 86400);
}
}
/**

View File

@@ -525,4 +525,14 @@ class DynamoDbStore implements LockProvider, Store
{
$this->prefix = ! empty($prefix) ? $prefix.':' : '';
}
/**
* Get the DynamoDb Client instance.
*
* @return DynamoDbClient
*/
public function getClient()
{
return $this->dynamo;
}
}

View File

@@ -3,13 +3,16 @@
namespace Illuminate\Cache;
use Exception;
use Illuminate\Contracts\Cache\LockProvider;
use Illuminate\Contracts\Cache\Store;
use Illuminate\Contracts\Filesystem\LockTimeoutException;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Filesystem\LockableFile;
use Illuminate\Support\InteractsWithTime;
class FileStore implements Store
class FileStore implements Store, LockProvider
{
use InteractsWithTime, RetrievesMultipleKeys;
use InteractsWithTime, HasCacheLock, RetrievesMultipleKeys;
/**
* The Illuminate Filesystem instance.
@@ -75,7 +78,7 @@ class FileStore implements Store
);
if ($result !== false && $result > 0) {
$this->ensureFileHasCorrectPermissions($path);
$this->ensurePermissionsAreCorrect($path);
return true;
}
@@ -83,6 +86,45 @@ class FileStore implements Store
return false;
}
/**
* Store an item in the cache if the key doesn't exist.
*
* @param string $key
* @param mixed $value
* @param int $seconds
* @return bool
*/
public function add($key, $value, $seconds)
{
$this->ensureCacheDirectoryExists($path = $this->path($key));
$file = new LockableFile($path, 'c+');
try {
$file->getExclusiveLock();
} catch (LockTimeoutException $e) {
$file->close();
return false;
}
$expire = $file->read(10);
if (empty($expire) || $this->currentTime() >= $expire) {
$file->truncate()
->write($this->expiration($seconds).serialize($value))
->close();
$this->ensurePermissionsAreCorrect($path);
return true;
}
$file->close();
return false;
}
/**
* Create the file cache directory if necessary.
*
@@ -91,18 +133,24 @@ class FileStore implements Store
*/
protected function ensureCacheDirectoryExists($path)
{
if (! $this->files->exists(dirname($path))) {
$this->files->makeDirectory(dirname($path), 0777, true, true);
$directory = dirname($path);
if (! $this->files->exists($directory)) {
$this->files->makeDirectory($directory, 0777, true, true);
// We're creating two levels of directories (e.g. 7e/24), so we check them both...
$this->ensurePermissionsAreCorrect($directory);
$this->ensurePermissionsAreCorrect(dirname($directory));
}
}
/**
* Ensure the cache file has the correct permissions.
* Ensure the created node has the correct permissions.
*
* @param string $path
* @return void
*/
protected function ensureFileHasCorrectPermissions($path)
protected function ensurePermissionsAreCorrect($path)
{
if (is_null($this->filePermission) ||
intval($this->files->chmod($path), 8) == $this->filePermission) {

View File

@@ -0,0 +1,31 @@
<?php
namespace Illuminate\Cache;
trait HasCacheLock
{
/**
* Get a lock instance.
*
* @param string $name
* @param int $seconds
* @param string|null $owner
* @return \Illuminate\Contracts\Cache\Lock
*/
public function lock($name, $seconds = 0, $owner = null)
{
return new CacheLock($this, $name, $seconds, $owner);
}
/**
* Restore a lock instance using the owner identifier.
*
* @param string $name
* @param string $owner
* @return \Illuminate\Contracts\Cache\Lock
*/
public function restoreLock($name, $owner)
{
return $this->lock($name, 0, $owner);
}
}

View File

@@ -105,7 +105,7 @@ abstract class Lock implements LockContract
*
* @param int $seconds
* @param callable|null $callback
* @return bool
* @return mixed
*
* @throws \Illuminate\Contracts\Cache\LockTimeoutException
*/
@@ -153,7 +153,7 @@ abstract class Lock implements LockContract
}
/**
* Specify the number of milliseconds to sleep in between blocked lock aquisition attempts.
* Specify the number of milliseconds to sleep in between blocked lock acquisition attempts.
*
* @param int $milliseconds
* @return $this

View File

@@ -0,0 +1,46 @@
<?php
namespace Illuminate\Cache;
class NoLock extends Lock
{
/**
* Attempt to acquire the lock.
*
* @return bool
*/
public function acquire()
{
return true;
}
/**
* Release the lock.
*
* @return bool
*/
public function release()
{
return true;
}
/**
* Releases this lock in disregard of ownership.
*
* @return void
*/
public function forceRelease()
{
//
}
/**
* Returns the owner value written into the driver for this lock.
*
* @return mixed
*/
protected function getCurrentOwner()
{
return $this->owner;
}
}

View File

@@ -2,7 +2,9 @@
namespace Illuminate\Cache;
class NullStore extends TaggableStore
use Illuminate\Contracts\Cache\LockProvider;
class NullStore extends TaggableStore implements LockProvider
{
use RetrievesMultipleKeys;
@@ -10,7 +12,7 @@ class NullStore extends TaggableStore
* Retrieve an item from the cache by key.
*
* @param string $key
* @return mixed
* @return void
*/
public function get($key)
{
@@ -35,7 +37,7 @@ class NullStore extends TaggableStore
*
* @param string $key
* @param mixed $value
* @return int|bool
* @return bool
*/
public function increment($key, $value = 1)
{
@@ -47,7 +49,7 @@ class NullStore extends TaggableStore
*
* @param string $key
* @param mixed $value
* @return int|bool
* @return bool
*/
public function decrement($key, $value = 1)
{
@@ -66,6 +68,31 @@ class NullStore extends TaggableStore
return false;
}
/**
* Get a lock instance.
*
* @param string $name
* @param int $seconds
* @param string|null $owner
* @return \Illuminate\Contracts\Cache\Lock
*/
public function lock($name, $seconds = 0, $owner = null)
{
return new NoLock($name, $seconds, $owner);
}
/**
* Restore a lock instance using the owner identifier.
*
* @param string $name
* @param string $owner
* @return \Illuminate\Contracts\Cache\Lock
*/
public function restoreLock($name, $owner)
{
return $this->lock($name, 0, $owner);
}
/**
* Remove an item from the cache.
*

View File

@@ -0,0 +1,35 @@
<?php
namespace Illuminate\Cache;
use Illuminate\Redis\Connections\PhpRedisConnection;
class PhpRedisLock extends RedisLock
{
/**
* Create a new phpredis lock instance.
*
* @param \Illuminate\Redis\Connections\PhpRedisConnection $redis
* @param string $name
* @param int $seconds
* @param string|null $owner
* @return void
*/
public function __construct(PhpRedisConnection $redis, string $name, int $seconds, ?string $owner = null)
{
parent::__construct($redis, $name, $seconds, $owner);
}
/**
* {@inheritDoc}
*/
public function release()
{
return (bool) $this->redis->eval(
LuaScripts::releaseLock(),
1,
$this->name,
...$this->redis->pack([$this->owner])
);
}
}

View File

@@ -2,6 +2,7 @@
namespace Illuminate\Cache;
use Closure;
use Illuminate\Contracts\Cache\Repository as Cache;
use Illuminate\Support\InteractsWithTime;
@@ -16,6 +17,13 @@ class RateLimiter
*/
protected $cache;
/**
* The configured limit object resolvers.
*
* @var array
*/
protected $limiters = [];
/**
* Create a new rate limiter instance.
*
@@ -27,6 +35,51 @@ class RateLimiter
$this->cache = $cache;
}
/**
* Register a named limiter configuration.
*
* @param string $name
* @param \Closure $callback
* @return $this
*/
public function for(string $name, Closure $callback)
{
$this->limiters[$name] = $callback;
return $this;
}
/**
* Get the given named rate limiter.
*
* @param string $name
* @return \Closure
*/
public function limiter(string $name)
{
return $this->limiters[$name] ?? null;
}
/**
* Attempts to execute a callback if it's not limited.
*
* @param string $key
* @param int $maxAttempts
* @param \Closure $callback
* @param int $decaySeconds
* @return mixed
*/
public function attempt($key, $maxAttempts, Closure $callback, $decaySeconds = 60)
{
if ($this->tooManyAttempts($key, $maxAttempts)) {
return false;
}
return tap($callback() ?: true, function () use ($key, $decaySeconds) {
$this->hit($key, $decaySeconds);
});
}
/**
* Determine if the given key has been "accessed" too many times.
*
@@ -36,6 +89,8 @@ class RateLimiter
*/
public function tooManyAttempts($key, $maxAttempts)
{
$key = $this->cleanRateLimiterKey($key);
if ($this->attempts($key) >= $maxAttempts) {
if ($this->cache->has($key.':timer')) {
return true;
@@ -56,6 +111,8 @@ class RateLimiter
*/
public function hit($key, $decaySeconds = 60)
{
$key = $this->cleanRateLimiterKey($key);
$this->cache->add(
$key.':timer', $this->availableAt($decaySeconds), $decaySeconds
);
@@ -79,6 +136,8 @@ class RateLimiter
*/
public function attempts($key)
{
$key = $this->cleanRateLimiterKey($key);
return $this->cache->get($key, 0);
}
@@ -90,9 +149,27 @@ class RateLimiter
*/
public function resetAttempts($key)
{
$key = $this->cleanRateLimiterKey($key);
return $this->cache->forget($key);
}
/**
* Get the number of retries left for the given key.
*
* @param string $key
* @param int $maxAttempts
* @return int
*/
public function remaining($key, $maxAttempts)
{
$key = $this->cleanRateLimiterKey($key);
$attempts = $this->attempts($key);
return $maxAttempts - $attempts;
}
/**
* Get the number of retries left for the given key.
*
@@ -102,9 +179,7 @@ class RateLimiter
*/
public function retriesLeft($key, $maxAttempts)
{
$attempts = $this->attempts($key);
return $maxAttempts - $attempts;
return $this->remaining($key, $maxAttempts);
}
/**
@@ -115,6 +190,8 @@ class RateLimiter
*/
public function clear($key)
{
$key = $this->cleanRateLimiterKey($key);
$this->resetAttempts($key);
$this->cache->forget($key.':timer');
@@ -128,6 +205,19 @@ class RateLimiter
*/
public function availableIn($key)
{
return $this->cache->get($key.':timer') - $this->currentTime();
$key = $this->cleanRateLimiterKey($key);
return max(0, $this->cache->get($key.':timer') - $this->currentTime());
}
/**
* Clean the rate limiter key from unicode characters.
*
* @param string $key
* @return string
*/
public function cleanRateLimiterKey($key)
{
return preg_replace('/&([a-z])[a-z]+;/i', '$1', htmlentities($key));
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace Illuminate\Cache\RateLimiting;
class GlobalLimit extends Limit
{
/**
* Create a new limit instance.
*
* @param int $maxAttempts
* @param int $decayMinutes
* @return void
*/
public function __construct(int $maxAttempts, int $decayMinutes = 1)
{
parent::__construct('', $maxAttempts, $decayMinutes);
}
}

View File

@@ -0,0 +1,132 @@
<?php
namespace Illuminate\Cache\RateLimiting;
class Limit
{
/**
* The rate limit signature key.
*
* @var mixed|string
*/
public $key;
/**
* The maximum number of attempts allowed within the given number of minutes.
*
* @var int
*/
public $maxAttempts;
/**
* The number of minutes until the rate limit is reset.
*
* @var int
*/
public $decayMinutes;
/**
* The response generator callback.
*
* @var callable
*/
public $responseCallback;
/**
* Create a new limit instance.
*
* @param mixed|string $key
* @param int $maxAttempts
* @param int $decayMinutes
* @return void
*/
public function __construct($key = '', int $maxAttempts = 60, int $decayMinutes = 1)
{
$this->key = $key;
$this->maxAttempts = $maxAttempts;
$this->decayMinutes = $decayMinutes;
}
/**
* Create a new rate limit.
*
* @param int $maxAttempts
* @return static
*/
public static function perMinute($maxAttempts)
{
return new static('', $maxAttempts);
}
/**
* Create a new rate limit using minutes as decay time.
*
* @param int $decayMinutes
* @param int $maxAttempts
* @return static
*/
public static function perMinutes($decayMinutes, $maxAttempts)
{
return new static('', $maxAttempts, $decayMinutes);
}
/**
* Create a new rate limit using hours as decay time.
*
* @param int $maxAttempts
* @param int $decayHours
* @return static
*/
public static function perHour($maxAttempts, $decayHours = 1)
{
return new static('', $maxAttempts, 60 * $decayHours);
}
/**
* Create a new rate limit using days as decay time.
*
* @param int $maxAttempts
* @param int $decayDays
* @return static
*/
public static function perDay($maxAttempts, $decayDays = 1)
{
return new static('', $maxAttempts, 60 * 24 * $decayDays);
}
/**
* Create a new unlimited rate limit.
*
* @return static
*/
public static function none()
{
return new Unlimited;
}
/**
* Set the key of the rate limit.
*
* @param string $key
* @return $this
*/
public function by($key)
{
$this->key = $key;
return $this;
}
/**
* Set the callback that should generate the response when the limit is exceeded.
*
* @param callable $callback
* @return $this
*/
public function response(callable $callback)
{
$this->responseCallback = $callback;
return $this;
}
}

View File

@@ -0,0 +1,16 @@
<?php
namespace Illuminate\Cache\RateLimiting;
class Unlimited extends GlobalLimit
{
/**
* Create a new limit instance.
*
* @return void
*/
public function __construct()
{
parent::__construct(PHP_INT_MAX);
}
}

View File

@@ -70,4 +70,14 @@ class RedisLock extends Lock
{
return $this->redis->get($this->name);
}
/**
* Get the name of the Redis connection being used to manage the lock.
*
* @return string
*/
public function getConnectionName()
{
return $this->redis->getName();
}
}

View File

@@ -4,6 +4,7 @@ namespace Illuminate\Cache;
use Illuminate\Contracts\Cache\LockProvider;
use Illuminate\Contracts\Redis\Factory as Redis;
use Illuminate\Redis\Connections\PhpRedisConnection;
class RedisStore extends TaggableStore implements LockProvider
{
@@ -22,12 +23,19 @@ class RedisStore extends TaggableStore implements LockProvider
protected $prefix;
/**
* The Redis connection that should be used.
* The Redis connection instance that should be used to manage locks.
*
* @var string
*/
protected $connection;
/**
* The name of the connection that should be used for locks.
*
* @var string
*/
protected $lockConnection;
/**
* Create a new Redis store.
*
@@ -181,7 +189,15 @@ class RedisStore extends TaggableStore implements LockProvider
*/
public function lock($name, $seconds = 0, $owner = null)
{
return new RedisLock($this->connection(), $this->prefix.$name, $seconds, $owner);
$lockName = $this->prefix.$name;
$lockConnection = $this->lockConnection();
if ($lockConnection instanceof PhpRedisConnection) {
return new PhpRedisLock($lockConnection, $lockName, $seconds, $owner);
}
return new RedisLock($lockConnection, $lockName, $seconds, $owner);
}
/**
@@ -243,7 +259,17 @@ class RedisStore extends TaggableStore implements LockProvider
}
/**
* Set the connection name to be used.
* Get the Redis connection instance that should be used to manage locks.
*
* @return \Illuminate\Redis\Connections\Connection
*/
public function lockConnection()
{
return $this->redis->connection($this->lockConnection ?? $this->connection);
}
/**
* Specify the name of the connection that should be used to store data.
*
* @param string $connection
* @return void
@@ -253,6 +279,19 @@ class RedisStore extends TaggableStore implements LockProvider
$this->connection = $connection;
}
/**
* Specify the name of the connection that should be used to manage locks.
*
* @param string $connection
* @return $this
*/
public function setLockConnection($connection)
{
$this->lockConnection = $connection;
return $this;
}
/**
* Get the Redis database instance.
*

View File

@@ -10,6 +10,7 @@ class RedisTaggedCache extends TaggedCache
* @var string
*/
const REFERENCE_KEY_FOREVER = 'forever_ref';
/**
* Standard reference key.
*
@@ -41,13 +42,13 @@ class RedisTaggedCache extends TaggedCache
*
* @param string $key
* @param mixed $value
* @return void
* @return int|bool
*/
public function increment($key, $value = 1)
{
$this->pushStandardKeys($this->tags->getNamespace(), $key);
parent::increment($key, $value);
return parent::increment($key, $value);
}
/**
@@ -55,13 +56,13 @@ class RedisTaggedCache extends TaggedCache
*
* @param string $key
* @param mixed $value
* @return void
* @return int|bool
*/
public function decrement($key, $value = 1)
{
$this->pushStandardKeys($this->tags->getNamespace(), $key);
parent::decrement($key, $value);
return parent::decrement($key, $value);
}
/**
@@ -88,7 +89,9 @@ class RedisTaggedCache extends TaggedCache
$this->deleteForeverKeys();
$this->deleteStandardKeys();
return parent::flush();
$this->tags->flush();
return true;
}
/**
@@ -175,13 +178,26 @@ class RedisTaggedCache extends TaggedCache
*/
protected function deleteValues($referenceKey)
{
$values = array_unique($this->store->connection()->smembers($referenceKey));
$cursor = $defaultCursorValue = '0';
if (count($values) > 0) {
foreach (array_chunk($values, 1000) as $valuesChunk) {
do {
[$cursor, $valuesChunk] = $this->store->connection()->sscan(
$referenceKey, $cursor, ['match' => '*', 'count' => 1000]
);
// PhpRedis client returns false if set does not exist or empty. Array destruction
// on false stores null in each variable. If valuesChunk is null, it means that
// there were not results from the previously executed "sscan" Redis command.
if (is_null($valuesChunk)) {
break;
}
$valuesChunk = array_unique($valuesChunk);
if (count($valuesChunk) > 0) {
$this->store->connection()->del(...$valuesChunk);
}
}
} while (((string) $cursor) !== $defaultCursorValue);
}
/**

View File

@@ -131,6 +131,8 @@ class Repository implements ArrayAccess, CacheContract
/**
* {@inheritdoc}
*
* @return iterable
*/
public function getMultiple($keys, $default = null)
{
@@ -219,6 +221,8 @@ class Repository implements ArrayAccess, CacheContract
/**
* {@inheritdoc}
*
* @return bool
*/
public function set($key, $value, $ttl = null)
{
@@ -276,6 +280,8 @@ class Repository implements ArrayAccess, CacheContract
/**
* {@inheritdoc}
*
* @return bool
*/
public function setMultiple($values, $ttl = null)
{
@@ -292,8 +298,12 @@ class Repository implements ArrayAccess, CacheContract
*/
public function add($key, $value, $ttl = null)
{
$seconds = null;
if ($ttl !== null) {
if ($this->getSeconds($ttl) <= 0) {
$seconds = $this->getSeconds($ttl);
if ($seconds <= 0) {
return false;
}
@@ -301,8 +311,6 @@ class Repository implements ArrayAccess, CacheContract
// has a chance to override this logic. Some drivers better support the way
// this operation should work with a total "atomic" implementation of it.
if (method_exists($this->store, 'add')) {
$seconds = $this->getSeconds($ttl);
return $this->store->add(
$this->itemKey($key), $value, $seconds
);
@@ -313,7 +321,7 @@ class Repository implements ArrayAccess, CacheContract
// so it exists for subsequent requests. Then, we will return true so it is
// easy to know if the value gets added. Otherwise, we will return false.
if (is_null($this->get($key))) {
return $this->put($key, $value, $ttl);
return $this->put($key, $value, $seconds);
}
return false;
@@ -365,7 +373,7 @@ class Repository implements ArrayAccess, CacheContract
* Get an item from the cache, or execute the given Closure and store the result.
*
* @param string $key
* @param \DateTimeInterface|\DateInterval|int|null $ttl
* @param \Closure|\DateTimeInterface|\DateInterval|int|null $ttl
* @param \Closure $callback
* @return mixed
*/
@@ -380,7 +388,7 @@ class Repository implements ArrayAccess, CacheContract
return $value;
}
$this->put($key, $value = $callback(), $ttl);
$this->put($key, $value = $callback(), value($ttl));
return $value;
}
@@ -437,6 +445,8 @@ class Repository implements ArrayAccess, CacheContract
/**
* {@inheritdoc}
*
* @return bool
*/
public function delete($key)
{
@@ -445,6 +455,8 @@ class Repository implements ArrayAccess, CacheContract
/**
* {@inheritdoc}
*
* @return bool
*/
public function deleteMultiple($keys)
{
@@ -461,6 +473,8 @@ class Repository implements ArrayAccess, CacheContract
/**
* {@inheritdoc}
*
* @return bool
*/
public function clear()
{
@@ -477,7 +491,7 @@ class Repository implements ArrayAccess, CacheContract
*/
public function tags($names)
{
if (! method_exists($this->store, 'tags')) {
if (! $this->supportsTags()) {
throw new BadMethodCallException('This cache store does not support tagging.');
}
@@ -501,6 +515,33 @@ class Repository implements ArrayAccess, CacheContract
return $key;
}
/**
* Calculate the number of seconds for the given TTL.
*
* @param \DateTimeInterface|\DateInterval|int $ttl
* @return int
*/
protected function getSeconds($ttl)
{
$duration = $this->parseDateInterval($ttl);
if ($duration instanceof DateTimeInterface) {
$duration = Carbon::now()->diffInRealSeconds($duration, false);
}
return (int) ($duration > 0 ? $duration : 0);
}
/**
* Determine if the current store supports tags.
*
* @return bool
*/
public function supportsTags()
{
return method_exists($this->store, 'tags');
}
/**
* Get the default cache time.
*
@@ -537,7 +578,7 @@ class Repository implements ArrayAccess, CacheContract
/**
* Fire an event for this cache instance.
*
* @param string $event
* @param object|string $event
* @return void
*/
protected function event($event)
@@ -574,6 +615,7 @@ class Repository implements ArrayAccess, CacheContract
* @param string $key
* @return bool
*/
#[\ReturnTypeWillChange]
public function offsetExists($key)
{
return $this->has($key);
@@ -585,6 +627,7 @@ class Repository implements ArrayAccess, CacheContract
* @param string $key
* @return mixed
*/
#[\ReturnTypeWillChange]
public function offsetGet($key)
{
return $this->get($key);
@@ -597,6 +640,7 @@ class Repository implements ArrayAccess, CacheContract
* @param mixed $value
* @return void
*/
#[\ReturnTypeWillChange]
public function offsetSet($key, $value)
{
$this->put($key, $value, $this->default);
@@ -608,28 +652,12 @@ class Repository implements ArrayAccess, CacheContract
* @param string $key
* @return void
*/
#[\ReturnTypeWillChange]
public function offsetUnset($key)
{
$this->forget($key);
}
/**
* Calculate the number of seconds for the given TTL.
*
* @param \DateTimeInterface|\DateInterval|int $ttl
* @return int
*/
protected function getSeconds($ttl)
{
$duration = $this->parseDateInterval($ttl);
if ($duration instanceof DateTimeInterface) {
$duration = Carbon::now()->diffInRealSeconds($duration, false);
}
return (int) $duration > 0 ? $duration : 0;
}
/**
* Handle dynamic calls into macros or pass missing methods to the store.
*

View File

@@ -16,8 +16,12 @@ trait RetrievesMultipleKeys
{
$return = [];
foreach ($keys as $key) {
$return[$key] = $this->get($key);
$keys = collect($keys)->mapWithKeys(function ($value, $key) {
return [is_string($key) ? $key : $value => is_string($key) ? $value : null];
})->all();
foreach ($keys as $key => $default) {
$return[$key] = $this->get($key, $default);
}
return $return;

View File

@@ -56,6 +56,26 @@ class TagSet
return $id;
}
/**
* Flush all the tags in the set.
*
* @return void
*/
public function flush()
{
array_walk($this->names, [$this, 'flushTag']);
}
/**
* Flush the tag from the cache.
*
* @param string $name
*/
public function flushTag($name)
{
$this->store->forget($this->tagKey($name));
}
/**
* Get a unique namespace that changes when any of the tags are flushed.
*

View File

@@ -52,11 +52,11 @@ class TaggedCache extends Repository
*
* @param string $key
* @param mixed $value
* @return void
* @return int|bool
*/
public function increment($key, $value = 1)
{
$this->store->increment($this->itemKey($key), $value);
return $this->store->increment($this->itemKey($key), $value);
}
/**
@@ -64,11 +64,11 @@ class TaggedCache extends Repository
*
* @param string $key
* @param mixed $value
* @return void
* @return int|bool
*/
public function decrement($key, $value = 1)
{
$this->store->decrement($this->itemKey($key), $value);
return $this->store->decrement($this->itemKey($key), $value);
}
/**
@@ -105,7 +105,7 @@ class TaggedCache extends Repository
/**
* Fire an event for this cache instance.
*
* @param string $event
* @param \Illuminate\Cache\Events\CacheEvent $event
* @return void
*/
protected function event($event)

View File

@@ -14,9 +14,14 @@
}
],
"require": {
"php": "^7.2.5|^8.0",
"illuminate/contracts": "^7.0",
"illuminate/support": "^7.0"
"php": "^7.3|^8.0",
"illuminate/collections": "^8.0",
"illuminate/contracts": "^8.0",
"illuminate/macroable": "^8.0",
"illuminate/support": "^8.0"
},
"provide": {
"psr/simple-cache-implementation": "1.0"
},
"autoload": {
"psr-4": {
@@ -25,15 +30,15 @@
},
"extra": {
"branch-alias": {
"dev-master": "7.x-dev"
"dev-master": "8.x-dev"
}
},
"suggest": {
"ext-memcached": "Required to use the memcache cache driver.",
"illuminate/database": "Required to use the database cache driver (^7.0).",
"illuminate/filesystem": "Required to use the file cache driver (^7.0).",
"illuminate/redis": "Required to use the redis cache driver (^7.0).",
"symfony/cache": "Required to PSR-6 cache bridge (^5.0)."
"illuminate/database": "Required to use the database cache driver (^8.0).",
"illuminate/filesystem": "Required to use the file cache driver (^8.0).",
"illuminate/redis": "Required to use the redis cache driver (^8.0).",
"symfony/cache": "Required to PSR-6 cache bridge (^5.4)."
},
"config": {
"sort-packages": true