From 4796555043fbc3806186c0f893c820e136f2ec7f Mon Sep 17 00:00:00 2001 From: Corey Taylor Date: Wed, 16 Jun 2021 13:17:49 -0500 Subject: [PATCH 001/127] Require php 8.0 and bump package dependency versions to 5.0 --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index f78e504ab..116148a02 100644 --- a/composer.json +++ b/composer.json @@ -22,8 +22,8 @@ "source": "https://github.com/cakephp/cache" }, "require": { - "php": ">=7.2.0", - "cakephp/core": "^4.0", + "php": ">=8.0", + "cakephp/core": "^5.0", "psr/simple-cache": "^1.0.0" }, "provide": { From adbfa052d6f203319478e311fb57e1a14a058bb5 Mon Sep 17 00:00:00 2001 From: Corey Taylor Date: Thu, 17 Jun 2021 22:44:36 -0500 Subject: [PATCH 002/127] Normalize order of union types in docblocks --- CacheRegistry.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CacheRegistry.php b/CacheRegistry.php index fb6d0ab06..464689737 100644 --- a/CacheRegistry.php +++ b/CacheRegistry.php @@ -64,7 +64,7 @@ protected function _throwMissingClassError(string $class, ?string $plugin): void * * Part of the template method for Cake\Core\ObjectRegistry::load() * - * @param string|\Cake\Cache\CacheEngine $class The classname or object to make. + * @param \Cake\Cache\CacheEngine|string $class The classname or object to make. * @param string $alias The alias of the object. * @param array $config An array of settings to use for the cache engine. * @return \Cake\Cache\CacheEngine The constructed CacheEngine class. From 5504acffac98c5ebacb6a99293a1bf0c1ccf69b7 Mon Sep 17 00:00:00 2001 From: Corey Taylor Date: Sat, 19 Jun 2021 20:55:55 -0500 Subject: [PATCH 003/127] Remove various deprecations --- Cache.php | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/Cache.php b/Cache.php index fabf32a3a..80d379942 100644 --- a/Cache.php +++ b/Cache.php @@ -197,20 +197,6 @@ protected static function _buildEngine(string $name): void } } - /** - * Get a cache engine object for the named cache config. - * - * @param string $config The name of the configured cache backend. - * @return \Psr\SimpleCache\CacheInterface&\Cake\Cache\CacheEngineInterface - * @deprecated 3.7.0 Use {@link pool()} instead. This method will be removed in 5.0. - */ - public static function engine(string $config) - { - deprecationWarning('Cache::engine() is deprecated. Use Cache::pool() instead.'); - - return static::pool($config); - } - /** * Get a SimpleCacheEngine object for the named cache pool. * From 8829fb077163e9d35c66837823fd25bdfb2c8fe2 Mon Sep 17 00:00:00 2001 From: Corey Taylor Date: Wed, 23 Jun 2021 01:29:01 -0500 Subject: [PATCH 004/127] Remove Wincache support --- Cache.php | 3 - Engine/WincacheEngine.php | 202 -------------------------------------- README.md | 1 - 3 files changed, 206 deletions(-) delete mode 100644 Engine/WincacheEngine.php diff --git a/Cache.php b/Cache.php index 80d379942..8826f8234 100644 --- a/Cache.php +++ b/Cache.php @@ -55,8 +55,6 @@ * - `MemcacheEngine` - Uses the PECL::Memcache extension and Memcached for storage. * Fast reads/writes, and benefits from memcache being distributed. * - `RedisEngine` - Uses redis and php-redis extension to store cache data. - * - `WincacheEngine` - Uses Windows Cache Extension for PHP. Supports wincache 1.1.0 and higher. - * This engine is recommended to people deploying on windows with IIS. * - `XcacheEngine` - Uses the Xcache extension, an alternative to APCu. * * See Cache engine documentation for expected configuration keys. @@ -81,7 +79,6 @@ class Cache 'memcached' => Engine\MemcachedEngine::class, 'null' => Engine\NullEngine::class, 'redis' => Engine\RedisEngine::class, - 'wincache' => Engine\WincacheEngine::class, ]; /** diff --git a/Engine/WincacheEngine.php b/Engine/WincacheEngine.php deleted file mode 100644 index 9d9e36eb6..000000000 --- a/Engine/WincacheEngine.php +++ /dev/null @@ -1,202 +0,0 @@ -_key($key); - $duration = $this->duration($ttl); - - return wincache_ucache_set($key, $value, $duration); - } - - /** - * Read a key from the cache - * - * @param string $key Identifier for the data - * @param mixed $default Default value to return if the key does not exist. - * @return mixed The cached data, or default value if the data doesn't exist, - * has expired, or if there was an error fetching it - */ - public function get($key, $default = null) - { - $value = wincache_ucache_get($this->_key($key), $success); - if ($success === false) { - return $default; - } - - return $value; - } - - /** - * Increments the value of an integer cached key - * - * @param string $key Identifier for the data - * @param int $offset How much to increment - * @return int|false New incremented value, false otherwise - */ - public function increment(string $key, int $offset = 1) - { - $key = $this->_key($key); - - return wincache_ucache_inc($key, $offset); - } - - /** - * Decrements the value of an integer cached key - * - * @param string $key Identifier for the data - * @param int $offset How much to subtract - * @return int|false New decremented value, false otherwise - */ - public function decrement(string $key, int $offset = 1) - { - $key = $this->_key($key); - - return wincache_ucache_dec($key, $offset); - } - - /** - * Delete a key from the cache - * - * @param string $key Identifier for the data - * @return bool True if the value was successfully deleted, false if it didn't exist or couldn't be removed - */ - public function delete($key): bool - { - $key = $this->_key($key); - - return wincache_ucache_delete($key); - } - - /** - * Delete all keys from the cache. This will clear every - * item in the cache matching the cache config prefix. - * - * @return bool True Returns true. - */ - public function clear(): bool - { - $info = wincache_ucache_info(); - $cacheKeys = $info['ucache_entries']; - unset($info); - foreach ($cacheKeys as $key) { - if (strpos($key['key_name'], $this->_config['prefix']) === 0) { - wincache_ucache_delete($key['key_name']); - } - } - - return true; - } - - /** - * Returns the `group value` for each of the configured groups - * If the group initial value was not found, then it initializes - * the group accordingly. - * - * @return string[] - */ - public function groups(): array - { - if (empty($this->_compiledGroupNames)) { - foreach ($this->_config['groups'] as $group) { - $this->_compiledGroupNames[] = $this->_config['prefix'] . $group; - } - } - - $groups = wincache_ucache_get($this->_compiledGroupNames); - if (count($groups) !== count($this->_config['groups'])) { - foreach ($this->_compiledGroupNames as $group) { - if (!isset($groups[$group])) { - wincache_ucache_set($group, 1); - $groups[$group] = 1; - } - } - ksort($groups); - } - - $result = []; - $groups = array_values($groups); - foreach ($this->_config['groups'] as $i => $group) { - $result[] = $group . $groups[$i]; - } - - return $result; - } - - /** - * Increments the group value to simulate deletion of all keys under a group - * old values will remain in storage until they expire. - * - * @param string $group The group to clear. - * @return bool success - */ - public function clearGroup(string $group): bool - { - $success = false; - wincache_ucache_inc($this->_config['prefix'] . $group, 1, $success); - - return $success; - } -} diff --git a/README.md b/README.md index 5f2c078bd..2f319dfe2 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,6 @@ The caching backends supported are: * APC * Memcached * Redis -* Wincache * Xcache ## Usage From 57dca48ae59fddc2671bfcd2b12a60a219b2b0d8 Mon Sep 17 00:00:00 2001 From: Corey Taylor Date: Wed, 14 Jul 2021 02:22:04 -0500 Subject: [PATCH 005/127] Convert single type[] array hints to array hints --- Cache.php | 4 ++-- CacheEngine.php | 2 +- Engine/ApcuEngine.php | 4 ++-- Engine/ArrayEngine.php | 2 +- Engine/MemcachedEngine.php | 4 ++-- Engine/RedisEngine.php | 2 +- Engine/WincacheEngine.php | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Cache.php b/Cache.php index fabf32a3a..ddc6269b6 100644 --- a/Cache.php +++ b/Cache.php @@ -71,7 +71,7 @@ class Cache * An array mapping URL schemes to fully qualified caching engine * class names. * - * @var string[] + * @var array * @psalm-var array */ protected static $_dsnClassMap = [ @@ -466,7 +466,7 @@ public static function clear(string $config = 'default'): bool /** * Delete all keys from the cache from all configurations. * - * @return bool[] Status code. For each configuration, it reports the status of the operation + * @return array Status code. For each configuration, it reports the status of the operation */ public static function clearAll(): array { diff --git a/CacheEngine.php b/CacheEngine.php index 56db69536..9c26353ee 100644 --- a/CacheEngine.php +++ b/CacheEngine.php @@ -317,7 +317,7 @@ abstract public function clearGroup(string $group): bool; * and returns the `group value` for each of them, this is * the token representing each group in the cache key * - * @return string[] + * @return array */ public function groups(): array { diff --git a/Engine/ApcuEngine.php b/Engine/ApcuEngine.php index 170ea4a43..085277953 100644 --- a/Engine/ApcuEngine.php +++ b/Engine/ApcuEngine.php @@ -29,7 +29,7 @@ class ApcuEngine extends CacheEngine * Contains the compiled group names * (prefixed with the global configuration prefix) * - * @var string[] + * @var array */ protected $_compiledGroupNames = []; @@ -183,7 +183,7 @@ public function add(string $key, $value): bool * If the group initial value was not found, then it initializes * the group accordingly. * - * @return string[] + * @return array * @link https://secure.php.net/manual/en/function.apcu-fetch.php * @link https://secure.php.net/manual/en/function.apcu-store.php */ diff --git a/Engine/ArrayEngine.php b/Engine/ArrayEngine.php index c33608204..9050537eb 100644 --- a/Engine/ArrayEngine.php +++ b/Engine/ArrayEngine.php @@ -152,7 +152,7 @@ public function clear(): bool * If the group initial value was not found, then it initializes * the group accordingly. * - * @return string[] + * @return array */ public function groups(): array { diff --git a/Engine/MemcachedEngine.php b/Engine/MemcachedEngine.php index 781c4cfc7..e0f273834 100644 --- a/Engine/MemcachedEngine.php +++ b/Engine/MemcachedEngine.php @@ -87,7 +87,7 @@ class MemcachedEngine extends CacheEngine protected $_serializers = []; /** - * @var string[] + * @var array */ protected $_compiledGroupNames = []; @@ -470,7 +470,7 @@ public function add(string $key, $value): bool * If the group initial value was not found, then it initializes * the group accordingly. * - * @return string[] + * @return array */ public function groups(): array { diff --git a/Engine/RedisEngine.php b/Engine/RedisEngine.php index 1eeed8cad..0a94bd94f 100644 --- a/Engine/RedisEngine.php +++ b/Engine/RedisEngine.php @@ -283,7 +283,7 @@ public function add(string $key, $value): bool * If the group initial value was not found, then it initializes * the group accordingly. * - * @return string[] + * @return array */ public function groups(): array { diff --git a/Engine/WincacheEngine.php b/Engine/WincacheEngine.php index 9d9e36eb6..4936f1188 100644 --- a/Engine/WincacheEngine.php +++ b/Engine/WincacheEngine.php @@ -155,7 +155,7 @@ public function clear(): bool * If the group initial value was not found, then it initializes * the group accordingly. * - * @return string[] + * @return array */ public function groups(): array { From 46326389ac0315a636f40a14b46b98d42ea9687b Mon Sep 17 00:00:00 2001 From: Corey Taylor Date: Sun, 11 Jul 2021 23:38:50 -0500 Subject: [PATCH 006/127] Add native type hints for Core --- CacheRegistry.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CacheRegistry.php b/CacheRegistry.php index 464689737..5435b71ea 100644 --- a/CacheRegistry.php +++ b/CacheRegistry.php @@ -70,7 +70,7 @@ protected function _throwMissingClassError(string $class, ?string $plugin): void * @return \Cake\Cache\CacheEngine The constructed CacheEngine class. * @throws \RuntimeException when an object doesn't implement the correct interface. */ - protected function _create($class, string $alias, array $config): CacheEngine + protected function _create(object|string $class, string $alias, array $config): CacheEngine { if (is_object($class)) { $instance = $class; From 9a053f5052139b29a057bd9c66e15e0162c87f9c Mon Sep 17 00:00:00 2001 From: Corey Taylor Date: Wed, 14 Jul 2021 22:11:22 -0500 Subject: [PATCH 007/127] Add native type hints for Cache --- Cache.php | 12 ++++++------ CacheEngine.php | 15 ++++++--------- CacheEngineInterface.php | 6 +++--- Engine/ApcuEngine.php | 8 ++++---- Engine/ArrayEngine.php | 4 ++-- Engine/FileEngine.php | 4 ++-- Engine/MemcachedEngine.php | 8 ++++---- Engine/NullEngine.php | 4 ++-- Engine/RedisEngine.php | 10 +++++----- 9 files changed, 34 insertions(+), 37 deletions(-) diff --git a/Cache.php b/Cache.php index 8330dd58f..0f618d8ac 100644 --- a/Cache.php +++ b/Cache.php @@ -239,7 +239,7 @@ public static function pool(string $config) * @param string $config Optional string configuration name to write to. Defaults to 'default' * @return bool True if the data was successfully cached, false on failure */ - public static function write(string $key, $value, string $config = 'default'): bool + public static function write(string $key, mixed $value, string $config = 'default'): bool { if (is_resource($value)) { return false; @@ -311,7 +311,7 @@ public static function writeMany(iterable $data, string $config = 'default'): bo * @return mixed The cached data, or null if the data doesn't exist, has expired, * or if there was an error fetching it. */ - public static function read(string $key, string $config = 'default') + public static function read(string $key, string $config = 'default'): mixed { return static::pool($config)->get($key); } @@ -354,7 +354,7 @@ public static function readMany(iterable $keys, string $config = 'default'): ite * or if there was an error fetching it. * @throws \Cake\Cache\InvalidArgumentException When offset < 0 */ - public static function increment(string $key, int $offset = 1, string $config = 'default') + public static function increment(string $key, int $offset = 1, string $config = 'default'): int|false { if ($offset < 0) { throw new InvalidArgumentException('Offset cannot be less than 0.'); @@ -373,7 +373,7 @@ public static function increment(string $key, int $offset = 1, string $config = * or if there was an error fetching it * @throws \Cake\Cache\InvalidArgumentException when offset < 0 */ - public static function decrement(string $key, int $offset = 1, string $config = 'default') + public static function decrement(string $key, int $offset = 1, string $config = 'default'): int|false { if ($offset < 0) { throw new InvalidArgumentException('Offset cannot be less than 0.'); @@ -566,7 +566,7 @@ public static function enabled(): bool * missing/expired, or an error. If the key is not found: boolean of the * success of the write */ - public static function remember(string $key, callable $callable, string $config = 'default') + public static function remember(string $key, callable $callable, string $config = 'default'): mixed { $existing = self::read($key, $config); if ($existing !== null) { @@ -601,7 +601,7 @@ public static function remember(string $key, callable $callable, string $config * @return bool True if the data was successfully cached, false on failure. * Or if the key existed already. */ - public static function add(string $key, $value, string $config = 'default'): bool + public static function add(string $key, mixed $value, string $config = 'default'): bool { if (is_resource($value)) { return false; diff --git a/CacheEngine.php b/CacheEngine.php index 9c26353ee..140c391e8 100644 --- a/CacheEngine.php +++ b/CacheEngine.php @@ -256,7 +256,7 @@ abstract public function set($key, $value, $ttl = null): bool; * @param int $offset How much to add * @return int|false New incremented value, false otherwise */ - abstract public function increment(string $key, int $offset = 1); + abstract public function increment(string $key, int $offset = 1): int|false; /** * Decrement a number under the key and return decremented value @@ -265,7 +265,7 @@ abstract public function increment(string $key, int $offset = 1); * @param int $offset How much to subtract * @return int|false New incremented value, false otherwise */ - abstract public function decrement(string $key, int $offset = 1); + abstract public function decrement(string $key, int $offset = 1): int|false; /** * Delete a key from the cache @@ -292,7 +292,7 @@ abstract public function clear(): bool; * @param mixed $value Data to be cached. * @return bool True if the data was successfully cached, false on failure. */ - public function add(string $key, $value): bool + public function add(string $key, mixed $value): bool { $cachedValue = $this->get($key); if ($cachedValue === null) { @@ -334,7 +334,7 @@ public function groups(): array * @return string Prefixed key with potentially unsafe characters replaced. * @throws \Cake\Cache\InvalidArgumentException If key's value is invalid. */ - protected function _key($key): string + protected function _key(string $key): string { $this->ensureValidKey($key); @@ -370,7 +370,7 @@ protected function warning(string $message): void * driver's default duration will be used. * @return int */ - protected function duration($ttl): int + protected function duration(DateInterval|int|null $ttl): int { if ($ttl === null) { return $this->_config['duration']; @@ -378,10 +378,7 @@ protected function duration($ttl): int if (is_int($ttl)) { return $ttl; } - if ($ttl instanceof DateInterval) { - return (int)$ttl->format('%s'); - } - throw new InvalidArgumentException('TTL values must be one of null, int, \DateInterval'); + return (int)$ttl->format('%s'); } } diff --git a/CacheEngineInterface.php b/CacheEngineInterface.php index d7eefe39f..d6e190646 100644 --- a/CacheEngineInterface.php +++ b/CacheEngineInterface.php @@ -35,7 +35,7 @@ interface CacheEngineInterface * @return bool True if the data was successfully cached, false on failure. * Or if the key existed already. */ - public function add(string $key, $value): bool; + public function add(string $key, mixed $value): bool; /** * Increment a number under the key and return incremented value @@ -44,7 +44,7 @@ public function add(string $key, $value): bool; * @param int $offset How much to add * @return int|false New incremented value, false otherwise */ - public function increment(string $key, int $offset = 1); + public function increment(string $key, int $offset = 1): int|false; /** * Decrement a number under the key and return decremented value @@ -53,7 +53,7 @@ public function increment(string $key, int $offset = 1); * @param int $offset How much to subtract * @return int|false New incremented value, false otherwise */ - public function decrement(string $key, int $offset = 1); + public function decrement(string $key, int $offset = 1): int|false; /** * Clear all values belonging to the named group. diff --git a/Engine/ApcuEngine.php b/Engine/ApcuEngine.php index 085277953..f40e5ba75 100644 --- a/Engine/ApcuEngine.php +++ b/Engine/ApcuEngine.php @@ -78,7 +78,7 @@ public function set($key, $value, $ttl = null): bool * has expired, or if there was an error fetching it * @link https://secure.php.net/manual/en/function.apcu-fetch.php */ - public function get($key, $default = null) + public function get($key, $default = null): mixed { $value = apcu_fetch($this->_key($key), $success); if ($success === false) { @@ -96,7 +96,7 @@ public function get($key, $default = null) * @return int|false New incremented value, false otherwise * @link https://secure.php.net/manual/en/function.apcu-inc.php */ - public function increment(string $key, int $offset = 1) + public function increment(string $key, int $offset = 1): int|false { $key = $this->_key($key); @@ -111,7 +111,7 @@ public function increment(string $key, int $offset = 1) * @return int|false New decremented value, false otherwise * @link https://secure.php.net/manual/en/function.apcu-dec.php */ - public function decrement(string $key, int $offset = 1) + public function decrement(string $key, int $offset = 1): int|false { $key = $this->_key($key); @@ -170,7 +170,7 @@ public function clear(): bool * @return bool True if the data was successfully cached, false on failure. * @link https://secure.php.net/manual/en/function.apcu-add.php */ - public function add(string $key, $value): bool + public function add(string $key, mixed $value): bool { $key = $this->_key($key); $duration = $this->_config['duration']; diff --git a/Engine/ArrayEngine.php b/Engine/ArrayEngine.php index 9050537eb..db72fa23c 100644 --- a/Engine/ArrayEngine.php +++ b/Engine/ArrayEngine.php @@ -92,7 +92,7 @@ public function get($key, $default = null) * @param int $offset How much to increment * @return int|false New incremented value, false otherwise */ - public function increment(string $key, int $offset = 1) + public function increment(string $key, int $offset = 1): int|false { if ($this->get($key) === null) { $this->set($key, 0); @@ -110,7 +110,7 @@ public function increment(string $key, int $offset = 1) * @param int $offset How much to subtract * @return int|false New decremented value, false otherwise */ - public function decrement(string $key, int $offset = 1) + public function decrement(string $key, int $offset = 1): int|false { if ($this->get($key) === null) { $this->set($key, 0); diff --git a/Engine/FileEngine.php b/Engine/FileEngine.php index 22ec33ce0..6672c7aa6 100644 --- a/Engine/FileEngine.php +++ b/Engine/FileEngine.php @@ -332,7 +332,7 @@ protected function _clearDirectory(string $path): void * @return int|false * @throws \LogicException */ - public function decrement(string $key, int $offset = 1) + public function decrement(string $key, int $offset = 1): int|false { throw new LogicException('Files cannot be atomically decremented.'); } @@ -345,7 +345,7 @@ public function decrement(string $key, int $offset = 1) * @return int|false * @throws \LogicException */ - public function increment(string $key, int $offset = 1) + public function increment(string $key, int $offset = 1): int|false { throw new LogicException('Files cannot be atomically incremented.'); } diff --git a/Engine/MemcachedEngine.php b/Engine/MemcachedEngine.php index e0f273834..17ae93c36 100644 --- a/Engine/MemcachedEngine.php +++ b/Engine/MemcachedEngine.php @@ -287,7 +287,7 @@ public function parseServerString(string $server): array * @return string|int|bool|null * @see https://secure.php.net/manual/en/memcached.getoption.php */ - public function getOption(int $name) + public function getOption(int $name): string|int|bool|null { return $this->_Memcached->getOption($name); } @@ -383,7 +383,7 @@ public function getMultiple($keys, $default = null): array * @param int $offset How much to increment * @return int|false New incremented value, false otherwise */ - public function increment(string $key, int $offset = 1) + public function increment(string $key, int $offset = 1): int|false { return $this->_Memcached->increment($this->_key($key), $offset); } @@ -395,7 +395,7 @@ public function increment(string $key, int $offset = 1) * @param int $offset How much to subtract * @return int|false New decremented value, false otherwise */ - public function decrement(string $key, int $offset = 1) + public function decrement(string $key, int $offset = 1): int|false { return $this->_Memcached->decrement($this->_key($key), $offset); } @@ -457,7 +457,7 @@ public function clear(): bool * @param mixed $value Data to be cached. * @return bool True if the data was successfully cached, false on failure. */ - public function add(string $key, $value): bool + public function add(string $key, mixed $value): bool { $duration = $this->_config['duration']; $key = $this->_key($key); diff --git a/Engine/NullEngine.php b/Engine/NullEngine.php index 4612a276b..85c292db7 100644 --- a/Engine/NullEngine.php +++ b/Engine/NullEngine.php @@ -68,7 +68,7 @@ public function getMultiple($keys, $default = null): iterable /** * @inheritDoc */ - public function increment(string $key, int $offset = 1) + public function increment(string $key, int $offset = 1): int|false { return 1; } @@ -76,7 +76,7 @@ public function increment(string $key, int $offset = 1) /** * @inheritDoc */ - public function decrement(string $key, int $offset = 1) + public function decrement(string $key, int $offset = 1): int|false { return 0; } diff --git a/Engine/RedisEngine.php b/Engine/RedisEngine.php index 0a94bd94f..3e4b983ea 100644 --- a/Engine/RedisEngine.php +++ b/Engine/RedisEngine.php @@ -181,7 +181,7 @@ public function get($key, $default = null) * @param int $offset How much to increment * @return int|false New incremented value, false otherwise */ - public function increment(string $key, int $offset = 1) + public function increment(string $key, int $offset = 1): int|false { $duration = $this->_config['duration']; $key = $this->_key($key); @@ -201,7 +201,7 @@ public function increment(string $key, int $offset = 1) * @param int $offset How much to subtract * @return int|false New decremented value, false otherwise */ - public function decrement(string $key, int $offset = 1) + public function decrement(string $key, int $offset = 1): int|false { $duration = $this->_config['duration']; $key = $this->_key($key); @@ -265,7 +265,7 @@ public function clear(): bool * @return bool True if the data was successfully cached, false on failure. * @link https://github.com/phpredis/phpredis#set */ - public function add(string $key, $value): bool + public function add(string $key, mixed $value): bool { $duration = $this->_config['duration']; $key = $this->_key($key); @@ -322,7 +322,7 @@ public function clearGroup(string $group): bool * @return string * @link https://github.com/phpredis/phpredis/issues/81 */ - protected function serialize($value): string + protected function serialize(mixed $value): string { if (is_int($value)) { return (string)$value; @@ -337,7 +337,7 @@ protected function serialize($value): string * @param string $value Value to unserialize. * @return mixed */ - protected function unserialize(string $value) + protected function unserialize(string $value): mixed { if (preg_match('/^[-]?\d+$/', $value)) { return (int)$value; From 64df16c78a486f586ec14ca16192d99bbdf1b10c Mon Sep 17 00:00:00 2001 From: mscherer Date: Tue, 31 Aug 2021 22:16:09 +0200 Subject: [PATCH 008/127] Start documenting the assoc arrays as per their string key. --- Cache.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cache.php b/Cache.php index ddc6269b6..01675a0b3 100644 --- a/Cache.php +++ b/Cache.php @@ -466,7 +466,7 @@ public static function clear(string $config = 'default'): bool /** * Delete all keys from the cache from all configurations. * - * @return array Status code. For each configuration, it reports the status of the operation + * @return array Status code. For each configuration, it reports the status of the operation */ public static function clearAll(): array { From 3b76a9b728f5bf1106bcec3c45f1e5e51c306d17 Mon Sep 17 00:00:00 2001 From: mscherer Date: Fri, 3 Sep 2021 16:00:27 +0200 Subject: [PATCH 009/127] Document the assoc arrays as per their string key. --- CacheEngine.php | 4 ++-- CacheRegistry.php | 2 +- Engine/ApcuEngine.php | 2 +- Engine/FileEngine.php | 4 ++-- Engine/MemcachedEngine.php | 4 ++-- Engine/RedisEngine.php | 4 ++-- Engine/WincacheEngine.php | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/CacheEngine.php b/CacheEngine.php index 9c26353ee..8e9fc613a 100644 --- a/CacheEngine.php +++ b/CacheEngine.php @@ -49,7 +49,7 @@ abstract class CacheEngine implements CacheInterface, CacheEngineInterface * - `warnOnWriteFailures` Some engines, such as ApcuEngine, may raise warnings on * write failures. * - * @var array + * @var array */ protected $_defaultConfig = [ 'duration' => 3600, @@ -72,7 +72,7 @@ abstract class CacheEngine implements CacheInterface, CacheEngineInterface * Called automatically by the cache frontend. Merge the runtime config with the defaults * before use. * - * @param array $config Associative array of parameters for the engine + * @param array $config Associative array of parameters for the engine * @return bool True if the engine has been successfully initialized, false if not */ public function init(array $config = []): bool diff --git a/CacheRegistry.php b/CacheRegistry.php index 464689737..c70835fc0 100644 --- a/CacheRegistry.php +++ b/CacheRegistry.php @@ -66,7 +66,7 @@ protected function _throwMissingClassError(string $class, ?string $plugin): void * * @param \Cake\Cache\CacheEngine|string $class The classname or object to make. * @param string $alias The alias of the object. - * @param array $config An array of settings to use for the cache engine. + * @param array $config An array of settings to use for the cache engine. * @return \Cake\Cache\CacheEngine The constructed CacheEngine class. * @throws \RuntimeException when an object doesn't implement the correct interface. */ diff --git a/Engine/ApcuEngine.php b/Engine/ApcuEngine.php index 085277953..bc90e8f0f 100644 --- a/Engine/ApcuEngine.php +++ b/Engine/ApcuEngine.php @@ -38,7 +38,7 @@ class ApcuEngine extends CacheEngine * * Called automatically by the cache frontend * - * @param array $config array of setting for the engine + * @param array $config array of setting for the engine * @return bool True if the engine has been successfully initialized, false if not */ public function init(array $config = []): bool diff --git a/Engine/FileEngine.php b/Engine/FileEngine.php index 22ec33ce0..e7ce5ea2c 100644 --- a/Engine/FileEngine.php +++ b/Engine/FileEngine.php @@ -57,7 +57,7 @@ class FileEngine extends CacheEngine * cache::gc from ever being called automatically. * - `serialize` Should cache objects be serialized first. * - * @var array + * @var array */ protected $_defaultConfig = [ 'duration' => 3600, @@ -81,7 +81,7 @@ class FileEngine extends CacheEngine * * Called automatically by the cache frontend. * - * @param array $config array of setting for the engine + * @param array $config array of setting for the engine * @return bool True if the engine has been successfully initialized, false if not */ public function init(array $config = []): bool diff --git a/Engine/MemcachedEngine.php b/Engine/MemcachedEngine.php index e0f273834..227161513 100644 --- a/Engine/MemcachedEngine.php +++ b/Engine/MemcachedEngine.php @@ -60,7 +60,7 @@ class MemcachedEngine extends CacheEngine * - `options` - Additional options for the memcached client. Should be an array of option => value. * Use the \Memcached::OPT_* constants as keys. * - * @var array + * @var array */ protected $_defaultConfig = [ 'compress' => false, @@ -96,7 +96,7 @@ class MemcachedEngine extends CacheEngine * * Called automatically by the cache frontend * - * @param array $config array of setting for the engine + * @param array $config array of setting for the engine * @return bool True if the engine has been successfully initialized, false if not * @throws \InvalidArgumentException When you try use authentication without * Memcached compiled with SASL support diff --git a/Engine/RedisEngine.php b/Engine/RedisEngine.php index 0a94bd94f..b7f0fec4b 100644 --- a/Engine/RedisEngine.php +++ b/Engine/RedisEngine.php @@ -51,7 +51,7 @@ class RedisEngine extends CacheEngine * - `timeout` timeout in seconds (float). * - `unix_socket` Path to the unix socket file (default: false) * - * @var array + * @var array */ protected $_defaultConfig = [ 'database' => 0, @@ -72,7 +72,7 @@ class RedisEngine extends CacheEngine * * Called automatically by the cache frontend * - * @param array $config array of setting for the engine + * @param array $config array of setting for the engine * @return bool True if the engine has been successfully initialized, false if not */ public function init(array $config = []): bool diff --git a/Engine/WincacheEngine.php b/Engine/WincacheEngine.php index 4936f1188..e9374b620 100644 --- a/Engine/WincacheEngine.php +++ b/Engine/WincacheEngine.php @@ -39,7 +39,7 @@ class WincacheEngine extends CacheEngine * * Called automatically by the cache frontend * - * @param array $config array of setting for the engine + * @param array $config array of setting for the engine * @return bool True if the engine has been successfully initialized, false if not */ public function init(array $config = []): bool From 2ae85e9290685b740b3e08971bf8268f7af2d955 Mon Sep 17 00:00:00 2001 From: Corey Taylor Date: Fri, 3 Sep 2021 15:08:40 -0500 Subject: [PATCH 010/127] Add native type hints for Cache properties --- Cache.php | 8 ++++---- CacheEngine.php | 4 ++-- Engine/ApcuEngine.php | 2 +- Engine/ArrayEngine.php | 2 +- Engine/FileEngine.php | 6 +++--- Engine/MemcachedEngine.php | 8 ++++---- Engine/RedisEngine.php | 6 +++--- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Cache.php b/Cache.php index 0f618d8ac..da17e0092 100644 --- a/Cache.php +++ b/Cache.php @@ -72,7 +72,7 @@ class Cache * @var array * @psalm-var array */ - protected static $_dsnClassMap = [ + protected static array $_dsnClassMap = [ 'array' => Engine\ArrayEngine::class, 'apcu' => Engine\ApcuEngine::class, 'file' => Engine\FileEngine::class, @@ -86,21 +86,21 @@ class Cache * * @var bool */ - protected static $_enabled = true; + protected static bool $_enabled = true; /** * Group to Config mapping * * @var array */ - protected static $_groups = []; + protected static array $_groups = []; /** * Cache Registry used for creating and using cache adapters. * * @var \Cake\Cache\CacheRegistry|null */ - protected static $_registry; + protected static ?CacheRegistry $_registry = null; /** * Returns the Cache Registry instance used for creating and using cache adapters. diff --git a/CacheEngine.php b/CacheEngine.php index 140c391e8..0d49fa576 100644 --- a/CacheEngine.php +++ b/CacheEngine.php @@ -51,7 +51,7 @@ abstract class CacheEngine implements CacheInterface, CacheEngineInterface * * @var array */ - protected $_defaultConfig = [ + protected array $_defaultConfig = [ 'duration' => 3600, 'groups' => [], 'prefix' => 'cake_', @@ -64,7 +64,7 @@ abstract class CacheEngine implements CacheInterface, CacheEngineInterface * * @var string */ - protected $_groupPrefix = ''; + protected string $_groupPrefix = ''; /** * Initialize the cache engine diff --git a/Engine/ApcuEngine.php b/Engine/ApcuEngine.php index f40e5ba75..4d3ec559c 100644 --- a/Engine/ApcuEngine.php +++ b/Engine/ApcuEngine.php @@ -31,7 +31,7 @@ class ApcuEngine extends CacheEngine * * @var array */ - protected $_compiledGroupNames = []; + protected array $_compiledGroupNames = []; /** * Initialize the Cache Engine diff --git a/Engine/ArrayEngine.php b/Engine/ArrayEngine.php index db72fa23c..602e388b7 100644 --- a/Engine/ArrayEngine.php +++ b/Engine/ArrayEngine.php @@ -37,7 +37,7 @@ class ArrayEngine extends CacheEngine * * @var array */ - protected $data = []; + protected array $data = []; /** * Write data for key into cache diff --git a/Engine/FileEngine.php b/Engine/FileEngine.php index 6672c7aa6..7931dd854 100644 --- a/Engine/FileEngine.php +++ b/Engine/FileEngine.php @@ -41,7 +41,7 @@ class FileEngine extends CacheEngine * * @var \SplFileObject|null */ - protected $_File; + protected ?SplFileObject $_File = null; /** * The default config used unless overridden by runtime configuration @@ -59,7 +59,7 @@ class FileEngine extends CacheEngine * * @var array */ - protected $_defaultConfig = [ + protected array $_defaultConfig = [ 'duration' => 3600, 'groups' => [], 'lock' => true, @@ -74,7 +74,7 @@ class FileEngine extends CacheEngine * * @var bool */ - protected $_init = true; + protected bool $_init = true; /** * Initialize File Cache Engine diff --git a/Engine/MemcachedEngine.php b/Engine/MemcachedEngine.php index 17ae93c36..d1c19830c 100644 --- a/Engine/MemcachedEngine.php +++ b/Engine/MemcachedEngine.php @@ -37,7 +37,7 @@ class MemcachedEngine extends CacheEngine * * @var \Memcached */ - protected $_Memcached; + protected Memcached $_Memcached; /** * The default config used unless overridden by runtime configuration @@ -62,7 +62,7 @@ class MemcachedEngine extends CacheEngine * * @var array */ - protected $_defaultConfig = [ + protected array $_defaultConfig = [ 'compress' => false, 'duration' => 3600, 'groups' => [], @@ -84,12 +84,12 @@ class MemcachedEngine extends CacheEngine * * @var array */ - protected $_serializers = []; + protected array $_serializers = []; /** * @var array */ - protected $_compiledGroupNames = []; + protected array $_compiledGroupNames = []; /** * Initialize the Cache Engine diff --git a/Engine/RedisEngine.php b/Engine/RedisEngine.php index 3e4b983ea..5e395411b 100644 --- a/Engine/RedisEngine.php +++ b/Engine/RedisEngine.php @@ -33,7 +33,7 @@ class RedisEngine extends CacheEngine * * @var \Redis */ - protected $_Redis; + protected Redis $_Redis; /** * The default config used unless overridden by runtime configuration @@ -53,7 +53,7 @@ class RedisEngine extends CacheEngine * * @var array */ - protected $_defaultConfig = [ + protected array $_defaultConfig = [ 'database' => 0, 'duration' => 3600, 'groups' => [], @@ -351,7 +351,7 @@ protected function unserialize(string $value): mixed */ public function __destruct() { - if (empty($this->_config['persistent']) && $this->_Redis instanceof Redis) { + if (empty($this->_config['persistent'])) { $this->_Redis->close(); } } From 15ffd28292153e3b8089bbcab35fc8159a639e01 Mon Sep 17 00:00:00 2001 From: ADmad Date: Sun, 12 Sep 2021 01:18:25 +0530 Subject: [PATCH 011/127] Fix docblock. --- Cache.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Cache.php b/Cache.php index fabf32a3a..56a9c34da 100644 --- a/Cache.php +++ b/Cache.php @@ -579,9 +579,8 @@ public static function enabled(): bool * the cache key is empty. Can be any callable type supported by your PHP. * @param string $config The cache configuration to use for this operation. * Defaults to default. - * @return mixed If the key is found: the cached data, false if the data - * missing/expired, or an error. If the key is not found: boolean of the - * success of the write + * @return mixed If the key is found: the cached data. + * If the key is not found the value returned by the callable. */ public static function remember(string $key, callable $callable, string $config = 'default') { From c3b63d7fe0bd0d277eec6f01bdd714d0157d1128 Mon Sep 17 00:00:00 2001 From: mscherer Date: Mon, 13 Sep 2021 10:54:59 +0200 Subject: [PATCH 012/127] Fix some grammar topics. --- Cache.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cache.php b/Cache.php index 01675a0b3..e5f7f0eb2 100644 --- a/Cache.php +++ b/Cache.php @@ -85,7 +85,7 @@ class Cache ]; /** - * Flag for tracking whether or not caching is enabled. + * Flag for tracking whether caching is enabled. * * @var bool */ @@ -548,7 +548,7 @@ public static function disable(): void } /** - * Check whether or not caching is enabled. + * Check whether caching is enabled. * * @return bool */ From 82ef650f52361d20af3641063cf18d521c6b915f Mon Sep 17 00:00:00 2001 From: ADmad Date: Mon, 13 Sep 2021 20:00:42 +0530 Subject: [PATCH 013/127] Use non-capturing catches where applicable. --- Engine/FileEngine.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Engine/FileEngine.php b/Engine/FileEngine.php index 617a6bc08..1c5f8e233 100644 --- a/Engine/FileEngine.php +++ b/Engine/FileEngine.php @@ -307,7 +307,7 @@ protected function _clearDirectory(string $path): void try { $file = new SplFileObject($path . $entry, 'r'); - } catch (Exception $e) { + } catch (Exception) { continue; } From 0e2f9cb84809ce53bc9991bafbdd7f49cef733c0 Mon Sep 17 00:00:00 2001 From: ADmad Date: Mon, 13 Sep 2021 22:06:10 +0530 Subject: [PATCH 014/127] Use new string functions instead of strpos(). --- Engine/ApcuEngine.php | 2 +- Engine/FileEngine.php | 7 ++----- Engine/MemcachedEngine.php | 4 ++-- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/Engine/ApcuEngine.php b/Engine/ApcuEngine.php index 44eef86cc..ef447dd67 100644 --- a/Engine/ApcuEngine.php +++ b/Engine/ApcuEngine.php @@ -153,7 +153,7 @@ public function clear(): bool $cache = apcu_cache_info(); // Raises warning by itself already foreach ($cache['cache_list'] as $key) { - if (strpos($key['info'], $this->_config['prefix']) === 0) { + if (str_starts_with($key['info'], $this->_config['prefix'])) { apcu_delete($key['info']); } } diff --git a/Engine/FileEngine.php b/Engine/FileEngine.php index 617a6bc08..15cf5d0e7 100644 --- a/Engine/FileEngine.php +++ b/Engine/FileEngine.php @@ -471,18 +471,15 @@ function (SplFileInfo $current) use ($group, $prefix) { return false; } - $hasPrefix = $prefix === '' - || strpos($current->getBasename(), $prefix) === 0; + $hasPrefix = $prefix === '' || str_starts_with($current->getBasename(), $prefix); if ($hasPrefix === false) { return false; } - $pos = strpos( + return str_contains( $current->getPathname(), DIRECTORY_SEPARATOR . $group . DIRECTORY_SEPARATOR ); - - return $pos !== false; } ); foreach ($filtered as $object) { diff --git a/Engine/MemcachedEngine.php b/Engine/MemcachedEngine.php index 33e40ba8d..f9a09a72e 100644 --- a/Engine/MemcachedEngine.php +++ b/Engine/MemcachedEngine.php @@ -259,7 +259,7 @@ protected function _setOptions(): void public function parseServerString(string $server): array { $socketTransport = 'unix://'; - if (strpos($server, $socketTransport) === 0) { + if (str_starts_with($server, $socketTransport)) { return [substr($server, strlen($socketTransport)), 0]; } if (substr($server, 0, 1) === '[') { @@ -442,7 +442,7 @@ public function clear(): bool } foreach ($keys as $key) { - if (strpos($key, $this->_config['prefix']) === 0) { + if (str_starts_with($key, $this->_config['prefix'])) { $this->_Memcached->delete($key); } } From 99a37b1196c1a0ca02bc6ae88ee3e07361ec62ce Mon Sep 17 00:00:00 2001 From: Corey Taylor Date: Thu, 16 Sep 2021 08:04:38 -0500 Subject: [PATCH 015/127] Add mixed return to cache engine get() --- CacheEngine.php | 2 +- Engine/ArrayEngine.php | 2 +- Engine/FileEngine.php | 2 +- Engine/MemcachedEngine.php | 2 +- Engine/NullEngine.php | 2 +- Engine/RedisEngine.php | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CacheEngine.php b/CacheEngine.php index e04b9ea80..b84189ade 100644 --- a/CacheEngine.php +++ b/CacheEngine.php @@ -233,7 +233,7 @@ public function has($key): bool * @return mixed The value of the item from the cache, or $default in case of cache miss. * @throws \Cake\Cache\InvalidArgumentException If the $key string is not a legal value. */ - abstract public function get($key, $default = null); + abstract public function get($key, $default = null): mixed; /** * Persists data in the cache, uniquely referenced by the given key with an optional expiration TTL time. diff --git a/Engine/ArrayEngine.php b/Engine/ArrayEngine.php index 602e388b7..41f6ff246 100644 --- a/Engine/ArrayEngine.php +++ b/Engine/ArrayEngine.php @@ -66,7 +66,7 @@ public function set($key, $value, $ttl = null): bool * @return mixed The cached data, or default value if the data doesn't exist, has * expired, or if there was an error fetching it. */ - public function get($key, $default = null) + public function get($key, $default = null): mixed { $key = $this->_key($key); if (!isset($this->data[$key])) { diff --git a/Engine/FileEngine.php b/Engine/FileEngine.php index 8a1d2b88d..c367a9b51 100644 --- a/Engine/FileEngine.php +++ b/Engine/FileEngine.php @@ -157,7 +157,7 @@ public function set($key, $value, $ttl = null): bool * @return mixed The cached data, or default value if the data doesn't exist, has * expired, or if there was an error fetching it */ - public function get($key, $default = null) + public function get($key, $default = null): mixed { $key = $this->_key($key); diff --git a/Engine/MemcachedEngine.php b/Engine/MemcachedEngine.php index f9a09a72e..3605c10f6 100644 --- a/Engine/MemcachedEngine.php +++ b/Engine/MemcachedEngine.php @@ -341,7 +341,7 @@ public function setMultiple($values, $ttl = null): bool * @return mixed The cached data, or default value if the data doesn't exist, has * expired, or if there was an error fetching it. */ - public function get($key, $default = null) + public function get($key, $default = null): mixed { $key = $this->_key($key); $value = $this->_Memcached->get($key); diff --git a/Engine/NullEngine.php b/Engine/NullEngine.php index 85c292db7..0413ac0dc 100644 --- a/Engine/NullEngine.php +++ b/Engine/NullEngine.php @@ -52,7 +52,7 @@ public function setMultiple($values, $ttl = null): bool /** * @inheritDoc */ - public function get($key, $default = null) + public function get($key, $default = null): mixed { return $default; } diff --git a/Engine/RedisEngine.php b/Engine/RedisEngine.php index 9ce818086..70637adf1 100644 --- a/Engine/RedisEngine.php +++ b/Engine/RedisEngine.php @@ -164,7 +164,7 @@ public function set($key, $value, $ttl = null): bool * @return mixed The cached data, or the default if the data doesn't exist, has * expired, or if there was an error fetching it */ - public function get($key, $default = null) + public function get($key, $default = null): mixed { $value = $this->_Redis->get($this->_key($key)); if ($value === false) { From 6dfe11a829fea480605c31502f6e46a281cd4940 Mon Sep 17 00:00:00 2001 From: mscherer Date: Fri, 17 Sep 2021 15:29:13 +0200 Subject: [PATCH 016/127] Fix up types in arrays of var def --- Cache.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cache.php b/Cache.php index e5f7f0eb2..e0ec4815e 100644 --- a/Cache.php +++ b/Cache.php @@ -71,7 +71,7 @@ class Cache * An array mapping URL schemes to fully qualified caching engine * class names. * - * @var array + * @var array * @psalm-var array */ protected static $_dsnClassMap = [ @@ -94,7 +94,7 @@ class Cache /** * Group to Config mapping * - * @var array + * @var array */ protected static $_groups = []; @@ -503,8 +503,8 @@ public static function clearGroup(string $group, string $config = 'default'): bo * $configs will equal to `['posts' => ['daily', 'weekly']]` * Calling this method will load all the configured engines. * - * @param string|null $group group name or null to retrieve all group mappings - * @return array map of group and all configuration that has the same group + * @param string|null $group Group name or null to retrieve all group mappings + * @return array Map of group and all configuration that has the same group * @throws \Cake\Cache\InvalidArgumentException */ public static function groupConfigs(?string $group = null): array From 88fcec0ecf19a0b678008e853d1443ded742b3f1 Mon Sep 17 00:00:00 2001 From: mscherer Date: Wed, 22 Sep 2021 17:00:51 +0200 Subject: [PATCH 017/127] Make docblock var definitions more concrete. --- Engine/MemcachedEngine.php | 2 +- Engine/WincacheEngine.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Engine/MemcachedEngine.php b/Engine/MemcachedEngine.php index 227161513..9bdd3638d 100644 --- a/Engine/MemcachedEngine.php +++ b/Engine/MemcachedEngine.php @@ -82,7 +82,7 @@ class MemcachedEngine extends CacheEngine * * Memcached must be compiled with JSON and igbinary support to use these engines * - * @var array + * @var array */ protected $_serializers = []; diff --git a/Engine/WincacheEngine.php b/Engine/WincacheEngine.php index e9374b620..ca0388e4b 100644 --- a/Engine/WincacheEngine.php +++ b/Engine/WincacheEngine.php @@ -30,7 +30,7 @@ class WincacheEngine extends CacheEngine * Contains the compiled group names * (prefixed with the global configuration prefix) * - * @var array + * @var array */ protected $_compiledGroupNames = []; From e6e98bd958dd2c20dac504b9c99342ae84c1e765 Mon Sep 17 00:00:00 2001 From: mscherer Date: Sun, 26 Sep 2021 02:10:05 +0200 Subject: [PATCH 018/127] Fix up doc typos or missing class links. --- Cache.php | 2 +- CacheRegistry.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cache.php b/Cache.php index 0c8d8d37f..412ad1f2d 100644 --- a/Cache.php +++ b/Cache.php @@ -33,7 +33,7 @@ * * ``` * Cache::config('shared', [ - * 'className' => Cake\Cache\Engine\ApcuEngine::class, + * 'className' => \Cake\Cache\Engine\ApcuEngine::class, * 'prefix' => 'my_app_' * ]); * ``` diff --git a/CacheRegistry.php b/CacheRegistry.php index c70835fc0..1c5aa4660 100644 --- a/CacheRegistry.php +++ b/CacheRegistry.php @@ -24,7 +24,7 @@ /** * An object registry for cache engines. * - * Used by Cake\Cache\Cache to load and manage cache engines. + * Used by {@link \Cake\Cache\Cache} to load and manage cache engines. * * @extends \Cake\Core\ObjectRegistry<\Cake\Cache\CacheEngine> */ From 61e8f5978f4f2b738bd4b1dcf78e030f5012f449 Mon Sep 17 00:00:00 2001 From: mscherer Date: Sun, 26 Sep 2021 12:24:37 +0200 Subject: [PATCH 019/127] Revert one change. --- Cache.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cache.php b/Cache.php index 412ad1f2d..0c8d8d37f 100644 --- a/Cache.php +++ b/Cache.php @@ -33,7 +33,7 @@ * * ``` * Cache::config('shared', [ - * 'className' => \Cake\Cache\Engine\ApcuEngine::class, + * 'className' => Cake\Cache\Engine\ApcuEngine::class, * 'prefix' => 'my_app_' * ]); * ``` From cd9b121e93ac30315b862efeb2f957e3450d862e Mon Sep 17 00:00:00 2001 From: Corey Taylor Date: Sun, 24 Oct 2021 15:02:24 -0500 Subject: [PATCH 020/127] Require php 7.4 for packages --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index f78e504ab..385a303b0 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ "source": "https://github.com/cakephp/cache" }, "require": { - "php": ">=7.2.0", + "php": ">=7.4.0", "cakephp/core": "^4.0", "psr/simple-cache": "^1.0.0" }, From 1fb7f767f0e5f7c8be0ce63bffb0f58ef624cff0 Mon Sep 17 00:00:00 2001 From: ADmad Date: Fri, 29 Oct 2021 19:14:02 +0530 Subject: [PATCH 021/127] Update to psr/simple-cache v2 & v3. --- CacheEngine.php | 16 ++++++++-------- Engine/ApcuEngine.php | 7 ++++--- Engine/ArrayEngine.php | 7 ++++--- Engine/FileEngine.php | 7 ++++--- Engine/MemcachedEngine.php | 15 ++++++++------- Engine/NullEngine.php | 13 +++++++------ Engine/RedisEngine.php | 7 ++++--- composer.json | 4 ++-- 8 files changed, 41 insertions(+), 35 deletions(-) diff --git a/CacheEngine.php b/CacheEngine.php index b84189ade..633134f61 100644 --- a/CacheEngine.php +++ b/CacheEngine.php @@ -135,11 +135,11 @@ protected function ensureValidType($iterable, string $check = self::CHECK_VALUE) * * @param iterable $keys A list of keys that can obtained in a single operation. * @param mixed $default Default value to return for keys that do not exist. - * @return iterable A list of key value pairs. Cache keys that do not exist or are stale will have $default as value. + * @return iterable A list of key value pairs. Cache keys that do not exist or are stale will have $default as value. * @throws \Cake\Cache\InvalidArgumentException If $keys is neither an array nor a Traversable, * or if any of the $keys are not a legal value. */ - public function getMultiple($keys, $default = null): iterable + public function getMultiple(iterable $keys, mixed $default = null): iterable { $this->ensureValidType($keys); @@ -162,7 +162,7 @@ public function getMultiple($keys, $default = null): iterable * @throws \Cake\Cache\InvalidArgumentException If $values is neither an array nor a Traversable, * or if any of the $values are not a legal value. */ - public function setMultiple($values, $ttl = null): bool + public function setMultiple(iterable $values, DateInterval|int|null $ttl = null): bool { $this->ensureValidType($values, self::CHECK_KEY); @@ -194,7 +194,7 @@ public function setMultiple($values, $ttl = null): bool * @throws \Cake\Cache\InvalidArgumentException If $keys is neither an array nor a Traversable, * or if any of the $keys are not a legal value. */ - public function deleteMultiple($keys): bool + public function deleteMultiple(iterable $keys): bool { $this->ensureValidType($keys); @@ -220,7 +220,7 @@ public function deleteMultiple($keys): bool * @return bool * @throws \Cake\Cache\InvalidArgumentException If the $key string is not a legal value. */ - public function has($key): bool + public function has(string $key): bool { return $this->get($key) !== null; } @@ -233,7 +233,7 @@ public function has($key): bool * @return mixed The value of the item from the cache, or $default in case of cache miss. * @throws \Cake\Cache\InvalidArgumentException If the $key string is not a legal value. */ - abstract public function get($key, $default = null): mixed; + abstract public function get(string $key, mixed $default = null): mixed; /** * Persists data in the cache, uniquely referenced by the given key with an optional expiration TTL time. @@ -247,7 +247,7 @@ abstract public function get($key, $default = null): mixed; * @throws \Cake\Cache\InvalidArgumentException * MUST be thrown if the $key string is not a legal value. */ - abstract public function set($key, $value, $ttl = null): bool; + abstract public function set(string $key, mixed $value, DateInterval|int|null $ttl = null): bool; /** * Increment a number under the key and return incremented value @@ -273,7 +273,7 @@ abstract public function decrement(string $key, int $offset = 1): int|false; * @param string $key Identifier for the data * @return bool True if the value was successfully deleted, false if it didn't exist or couldn't be removed */ - abstract public function delete($key): bool; + abstract public function delete(string $key): bool; /** * Delete all keys from the cache diff --git a/Engine/ApcuEngine.php b/Engine/ApcuEngine.php index ef447dd67..cd7753f34 100644 --- a/Engine/ApcuEngine.php +++ b/Engine/ApcuEngine.php @@ -18,6 +18,7 @@ use APCUIterator; use Cake\Cache\CacheEngine; +use DateInterval; use RuntimeException; /** @@ -61,7 +62,7 @@ public function init(array $config = []): bool * @return bool True on success and false on failure. * @link https://secure.php.net/manual/en/function.apcu-store.php */ - public function set($key, $value, $ttl = null): bool + public function set(string $key, mixed $value, DateInterval|int|null $ttl = null): bool { $key = $this->_key($key); $duration = $this->duration($ttl); @@ -78,7 +79,7 @@ public function set($key, $value, $ttl = null): bool * has expired, or if there was an error fetching it * @link https://secure.php.net/manual/en/function.apcu-fetch.php */ - public function get($key, $default = null): mixed + public function get(string $key, mixed $default = null): mixed { $value = apcu_fetch($this->_key($key), $success); if ($success === false) { @@ -125,7 +126,7 @@ public function decrement(string $key, int $offset = 1): int|false * @return bool True if the value was successfully deleted, false if it didn't exist or couldn't be removed * @link https://secure.php.net/manual/en/function.apcu-delete.php */ - public function delete($key): bool + public function delete(string $key): bool { $key = $this->_key($key); diff --git a/Engine/ArrayEngine.php b/Engine/ArrayEngine.php index 41f6ff246..1f89721a0 100644 --- a/Engine/ArrayEngine.php +++ b/Engine/ArrayEngine.php @@ -17,6 +17,7 @@ namespace Cake\Cache\Engine; use Cake\Cache\CacheEngine; +use DateInterval; /** * Array storage engine for cache. @@ -49,7 +50,7 @@ class ArrayEngine extends CacheEngine * for it or let the driver take care of that. * @return bool True on success and false on failure. */ - public function set($key, $value, $ttl = null): bool + public function set(string $key, mixed $value, DateInterval|int|null $ttl = null): bool { $key = $this->_key($key); $expires = time() + $this->duration($ttl); @@ -66,7 +67,7 @@ public function set($key, $value, $ttl = null): bool * @return mixed The cached data, or default value if the data doesn't exist, has * expired, or if there was an error fetching it. */ - public function get($key, $default = null): mixed + public function get(string $key, mixed $default = null): mixed { $key = $this->_key($key); if (!isset($this->data[$key])) { @@ -127,7 +128,7 @@ public function decrement(string $key, int $offset = 1): int|false * @param string $key Identifier for the data * @return bool True if the value was successfully deleted, false if it didn't exist or couldn't be removed */ - public function delete($key): bool + public function delete(string $key): bool { $key = $this->_key($key); unset($this->data[$key]); diff --git a/Engine/FileEngine.php b/Engine/FileEngine.php index c367a9b51..531a010df 100644 --- a/Engine/FileEngine.php +++ b/Engine/FileEngine.php @@ -19,6 +19,7 @@ use Cake\Cache\CacheEngine; use Cake\Cache\InvalidArgumentException; use CallbackFilterIterator; +use DateInterval; use Exception; use FilesystemIterator; use LogicException; @@ -111,7 +112,7 @@ public function init(array $config = []): bool * for it or let the driver take care of that. * @return bool True on success and false on failure. */ - public function set($key, $value, $ttl = null): bool + public function set(string $key, mixed $value, DateInterval|int|null $ttl = null): bool { if ($value === '' || !$this->_init) { return false; @@ -157,7 +158,7 @@ public function set($key, $value, $ttl = null): bool * @return mixed The cached data, or default value if the data doesn't exist, has * expired, or if there was an error fetching it */ - public function get($key, $default = null): mixed + public function get(string $key, mixed $default = null): mixed { $key = $this->_key($key); @@ -211,7 +212,7 @@ public function get($key, $default = null): mixed * @return bool True if the value was successfully deleted, false if it didn't * exist or couldn't be removed */ - public function delete($key): bool + public function delete(string $key): bool { $key = $this->_key($key); diff --git a/Engine/MemcachedEngine.php b/Engine/MemcachedEngine.php index 7c3f0f76f..c87512140 100644 --- a/Engine/MemcachedEngine.php +++ b/Engine/MemcachedEngine.php @@ -17,6 +17,7 @@ namespace Cake\Cache\Engine; use Cake\Cache\CacheEngine; +use DateInterval; use InvalidArgumentException; use Memcached; use RuntimeException; @@ -306,7 +307,7 @@ public function getOption(int $name): string|int|bool|null * @return bool True if the data was successfully cached, false on failure * @see https://www.php.net/manual/en/memcached.set.php */ - public function set($key, $value, $ttl = null): bool + public function set(string $key, mixed $value, DateInterval|int|null $ttl = null): bool { $duration = $this->duration($ttl); @@ -322,7 +323,7 @@ public function set($key, $value, $ttl = null): bool * for it or let the driver take care of that. * @return bool Whether the write was successful or not. */ - public function setMultiple($values, $ttl = null): bool + public function setMultiple(iterable $values, DateInterval|int|null $ttl = null): bool { $cacheData = []; foreach ($values as $key => $value) { @@ -341,7 +342,7 @@ public function setMultiple($values, $ttl = null): bool * @return mixed The cached data, or default value if the data doesn't exist, has * expired, or if there was an error fetching it. */ - public function get($key, $default = null): mixed + public function get(string $key, mixed $default = null): mixed { $key = $this->_key($key); $value = $this->_Memcached->get($key); @@ -357,10 +358,10 @@ public function get($key, $default = null): mixed * * @param iterable $keys An array of identifiers for the data * @param mixed $default Default value to return for keys that do not exist. - * @return array An array containing, for each of the given $keys, the cached data or + * @return iterable An array containing, for each of the given $keys, the cached data or * false if cached data could not be retrieved. */ - public function getMultiple($keys, $default = null): array + public function getMultiple(iterable $keys, mixed $default = null): iterable { $cacheKeys = []; foreach ($keys as $key) { @@ -407,7 +408,7 @@ public function decrement(string $key, int $offset = 1): int|false * @return bool True if the value was successfully deleted, false if it didn't * exist or couldn't be removed. */ - public function delete($key): bool + public function delete(string $key): bool { return $this->_Memcached->delete($this->_key($key)); } @@ -419,7 +420,7 @@ public function delete($key): bool * @return bool of boolean values that are true if the key was successfully * deleted, false if it didn't exist or couldn't be removed. */ - public function deleteMultiple($keys): bool + public function deleteMultiple(iterable $keys): bool { $cacheKeys = []; foreach ($keys as $key) { diff --git a/Engine/NullEngine.php b/Engine/NullEngine.php index 0413ac0dc..bc2f06720 100644 --- a/Engine/NullEngine.php +++ b/Engine/NullEngine.php @@ -17,6 +17,7 @@ namespace Cake\Cache\Engine; use Cake\Cache\CacheEngine; +use DateInterval; /** * Null cache engine, all operations appear to work, but do nothing. @@ -36,7 +37,7 @@ public function init(array $config = []): bool /** * @inheritDoc */ - public function set($key, $value, $ttl = null): bool + public function set(string $key, mixed $value, DateInterval|int|null $ttl = null): bool { return true; } @@ -44,7 +45,7 @@ public function set($key, $value, $ttl = null): bool /** * @inheritDoc */ - public function setMultiple($values, $ttl = null): bool + public function setMultiple(iterable $values, DateInterval|int|null $ttl = null): bool { return true; } @@ -52,7 +53,7 @@ public function setMultiple($values, $ttl = null): bool /** * @inheritDoc */ - public function get($key, $default = null): mixed + public function get(string $key, mixed $default = null): mixed { return $default; } @@ -60,7 +61,7 @@ public function get($key, $default = null): mixed /** * @inheritDoc */ - public function getMultiple($keys, $default = null): iterable + public function getMultiple(iterable $keys, mixed $default = null): iterable { return []; } @@ -84,7 +85,7 @@ public function decrement(string $key, int $offset = 1): int|false /** * @inheritDoc */ - public function delete($key): bool + public function delete(string $key): bool { return true; } @@ -92,7 +93,7 @@ public function delete($key): bool /** * @inheritDoc */ - public function deleteMultiple($keys): bool + public function deleteMultiple(iterable $keys): bool { return true; } diff --git a/Engine/RedisEngine.php b/Engine/RedisEngine.php index 70637adf1..8eac9cbb0 100644 --- a/Engine/RedisEngine.php +++ b/Engine/RedisEngine.php @@ -19,6 +19,7 @@ use Cake\Cache\CacheEngine; use Cake\Log\Log; +use DateInterval; use Redis; use RedisException; use RuntimeException; @@ -143,7 +144,7 @@ protected function _connect(): bool * for it or let the driver take care of that. * @return bool True if the data was successfully cached, false on failure */ - public function set($key, $value, $ttl = null): bool + public function set(string $key, mixed $value, DateInterval|int|null $ttl = null): bool { $key = $this->_key($key); $value = $this->serialize($value); @@ -164,7 +165,7 @@ public function set($key, $value, $ttl = null): bool * @return mixed The cached data, or the default if the data doesn't exist, has * expired, or if there was an error fetching it */ - public function get($key, $default = null): mixed + public function get(string $key, mixed $default = null): mixed { $value = $this->_Redis->get($this->_key($key)); if ($value === false) { @@ -220,7 +221,7 @@ public function decrement(string $key, int $offset = 1): int|false * @param string $key Identifier for the data * @return bool True if the value was successfully deleted, false if it didn't exist or couldn't be removed */ - public function delete($key): bool + public function delete(string $key): bool { $key = $this->_key($key); diff --git a/composer.json b/composer.json index 116148a02..16e0b7d80 100644 --- a/composer.json +++ b/composer.json @@ -24,10 +24,10 @@ "require": { "php": ">=8.0", "cakephp/core": "^5.0", - "psr/simple-cache": "^1.0.0" + "psr/simple-cache": "^2.0 || ^3.0" }, "provide": { - "psr/simple-cache-implementation": "^1.0.0" + "psr/simple-cache-implementation": "^3.0" }, "autoload": { "psr-4": { From 954f70056636f429801aae68d4e20caf47d88098 Mon Sep 17 00:00:00 2001 From: ADmad Date: Tue, 2 Nov 2021 01:03:05 +0530 Subject: [PATCH 022/127] Remove unneded psalm error suppressions. --- Engine/MemcachedEngine.php | 1 - 1 file changed, 1 deletion(-) diff --git a/Engine/MemcachedEngine.php b/Engine/MemcachedEngine.php index c87512140..f14ecc636 100644 --- a/Engine/MemcachedEngine.php +++ b/Engine/MemcachedEngine.php @@ -135,7 +135,6 @@ public function init(array $config = []): bool $this->_config['servers'] = [$this->_config['servers']]; } - /** @psalm-suppress RedundantPropertyInitializationCheck */ if (isset($this->_Memcached)) { return true; } From 40006443c445be74d05fc1478db09d6ce3841bab Mon Sep 17 00:00:00 2001 From: Corey Taylor Date: Wed, 15 Dec 2021 07:39:40 -0600 Subject: [PATCH 023/127] Add or suppress missing parameter type declarations --- CacheEngine.php | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/CacheEngine.php b/CacheEngine.php index 633134f61..50c2a282f 100644 --- a/CacheEngine.php +++ b/CacheEngine.php @@ -93,11 +93,11 @@ public function init(array $config = []): bool /** * Ensure the validity of the given cache key. * - * @param string $key Key to check. + * @param mixed $key Key to check. * @return void * @throws \Cake\Cache\InvalidArgumentException When the key is not valid. */ - protected function ensureValidKey($key): void + protected function ensureValidKey(mixed $key): void { if (!is_string($key) || strlen($key) === 0) { throw new InvalidArgumentException('A cache key must be a non-empty string.'); @@ -112,15 +112,8 @@ protected function ensureValidKey($key): void * @return void * @throws \Cake\Cache\InvalidArgumentException */ - protected function ensureValidType($iterable, string $check = self::CHECK_VALUE): void + protected function ensureValidType(iterable $iterable, string $check = self::CHECK_VALUE): void { - if (!is_iterable($iterable)) { - throw new InvalidArgumentException(sprintf( - 'A cache %s must be either an array or a Traversable.', - $check === self::CHECK_VALUE ? 'key set' : 'set' - )); - } - foreach ($iterable as $key => $value) { if ($check === self::CHECK_VALUE) { $this->ensureValidKey($value); From 02064cc6e9b47a2295c4944afa8b540e75ffa935 Mon Sep 17 00:00:00 2001 From: ADmad Date: Fri, 17 Dec 2021 19:58:04 +0530 Subject: [PATCH 024/127] Revert "Merge branch '4.x' into 4.next" This reverts commit de4eb4f06bb7a7b8512bb4d7ac939e4f63e9a578, reversing changes made to c2e3db0eef03b730cfc5c41eedf9fae64427e59b. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 385a303b0..f78e504ab 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ "source": "https://github.com/cakephp/cache" }, "require": { - "php": ">=7.4.0", + "php": ">=7.2.0", "cakephp/core": "^4.0", "psr/simple-cache": "^1.0.0" }, From e546384e2a362c7cd9da12457fb0b9ef6b2a2434 Mon Sep 17 00:00:00 2001 From: ADmad Date: Sat, 18 Dec 2021 18:32:04 +0530 Subject: [PATCH 025/127] Revert "Revert "Merge branch '4.x' into 4.next"" This reverts commit 2a3c42e6f4a6e3235c089ff440c0920ddbfdfb24. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index f78e504ab..385a303b0 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ "source": "https://github.com/cakephp/cache" }, "require": { - "php": ">=7.2.0", + "php": ">=7.4.0", "cakephp/core": "^4.0", "psr/simple-cache": "^1.0.0" }, From 0bc1d264b47ae8df51f4c6680d89edf38ac5c5c1 Mon Sep 17 00:00:00 2001 From: ADmad Date: Wed, 26 Jan 2022 17:44:58 +0530 Subject: [PATCH 026/127] Allow v2 of psr/log and psr/simple-cache. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index f78e504ab..001a8a9dc 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "require": { "php": ">=7.2.0", "cakephp/core": "^4.0", - "psr/simple-cache": "^1.0.0" + "psr/simple-cache": "^1.0 || ^2.0" }, "provide": { "psr/simple-cache-implementation": "^1.0.0" From 94a4fda939d218cacfbdd36609eecfe13141789b Mon Sep 17 00:00:00 2001 From: ADmad Date: Thu, 3 Feb 2022 19:44:49 +0530 Subject: [PATCH 027/127] Fix errors reported by static analyzers --- Engine/MemcachedEngine.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Engine/MemcachedEngine.php b/Engine/MemcachedEngine.php index 9bdd3638d..b714f5056 100644 --- a/Engine/MemcachedEngine.php +++ b/Engine/MemcachedEngine.php @@ -134,11 +134,6 @@ public function init(array $config = []): bool $this->_config['servers'] = [$this->_config['servers']]; } - /** @psalm-suppress RedundantPropertyInitializationCheck */ - if (isset($this->_Memcached)) { - return true; - } - if ($this->_config['persistent']) { $this->_Memcached = new Memcached($this->_config['persistent']); } else { From f55a011ed643cd3e0a7add86ebb2512c5373539e Mon Sep 17 00:00:00 2001 From: mscherer Date: Fri, 4 Feb 2022 15:48:41 +0100 Subject: [PATCH 028/127] Fix PHPStan found issues around mixed and object usage. --- Engine/FileEngine.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Engine/FileEngine.php b/Engine/FileEngine.php index 531a010df..b0997cdc2 100644 --- a/Engine/FileEngine.php +++ b/Engine/FileEngine.php @@ -465,6 +465,7 @@ public function clearGroup(string $group): bool $directoryIterator, RecursiveIteratorIterator::CHILD_FIRST ); + /** @var array $filtered */ $filtered = new CallbackFilterIterator( $contents, function (SplFileInfo $current) use ($group, $prefix) { From f8d702c1203f94c22367d3b168209c9154087379 Mon Sep 17 00:00:00 2001 From: mscherer Date: Fri, 4 Feb 2022 16:00:22 +0100 Subject: [PATCH 029/127] Fix PHPStan found issues around mixed and object usage. --- Engine/FileEngine.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Engine/FileEngine.php b/Engine/FileEngine.php index b0997cdc2..e8e68a4d6 100644 --- a/Engine/FileEngine.php +++ b/Engine/FileEngine.php @@ -465,7 +465,7 @@ public function clearGroup(string $group): bool $directoryIterator, RecursiveIteratorIterator::CHILD_FIRST ); - /** @var array $filtered */ + /** @var array<\SplFileInfo> $filtered */ $filtered = new CallbackFilterIterator( $contents, function (SplFileInfo $current) use ($group, $prefix) { From ad09e77bba2ad205f7c4017e04b5d8065816cb10 Mon Sep 17 00:00:00 2001 From: ADmad Date: Sat, 5 Feb 2022 13:57:51 +0530 Subject: [PATCH 030/127] Remove unneeded null type from properties. --- Cache.php | 10 +++++----- Engine/FileEngine.php | 20 ++++++++------------ 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/Cache.php b/Cache.php index 7c7c8f4d3..a056a0a14 100644 --- a/Cache.php +++ b/Cache.php @@ -98,9 +98,9 @@ class Cache /** * Cache Registry used for creating and using cache adapters. * - * @var \Cake\Cache\CacheRegistry|null + * @var \Cake\Cache\CacheRegistry */ - protected static ?CacheRegistry $_registry = null; + protected static CacheRegistry $_registry; /** * Returns the Cache Registry instance used for creating and using cache adapters. @@ -109,11 +109,11 @@ class Cache */ public static function getRegistry(): CacheRegistry { - if (static::$_registry === null) { - static::$_registry = new CacheRegistry(); + if (isset(static::$_registry)) { + return static::$_registry; } - return static::$_registry; + return static::$_registry = new CacheRegistry(); } /** diff --git a/Engine/FileEngine.php b/Engine/FileEngine.php index 531a010df..32ebec39e 100644 --- a/Engine/FileEngine.php +++ b/Engine/FileEngine.php @@ -40,9 +40,9 @@ class FileEngine extends CacheEngine /** * Instance of SplFileObject class * - * @var \SplFileObject|null + * @var \SplFileObject */ - protected ?SplFileObject $_File = null; + protected SplFileObject $_File; /** * The default config used unless overridden by runtime configuration @@ -132,11 +132,9 @@ public function set(string $key, mixed $value, DateInterval|int|null $ttl = null $contents = implode([$expires, PHP_EOL, $value, PHP_EOL]); if ($this->_config['lock']) { - /** @psalm-suppress PossiblyNullReference */ $this->_File->flock(LOCK_EX); } - /** @psalm-suppress PossiblyNullReference */ $this->_File->rewind(); $success = $this->_File->ftruncate(0) && $this->_File->fwrite($contents) && @@ -145,7 +143,7 @@ public function set(string $key, mixed $value, DateInterval|int|null $ttl = null if ($this->_config['lock']) { $this->_File->flock(LOCK_UN); } - $this->_File = null; + unset($this->_File); return $success; } @@ -167,11 +165,9 @@ public function get(string $key, mixed $default = null): mixed } if ($this->_config['lock']) { - /** @psalm-suppress PossiblyNullReference */ $this->_File->flock(LOCK_SH); } - /** @psalm-suppress PossiblyNullReference */ $this->_File->rewind(); $time = time(); $cachetime = (int)$this->_File->current(); @@ -220,9 +216,8 @@ public function delete(string $key): bool return false; } - /** @psalm-suppress PossiblyNullReference */ $path = $this->_File->getRealPath(); - $this->_File = null; + unset($this->_File); // phpcs:disable return @unlink($path); @@ -239,7 +234,7 @@ public function clear(): bool if (!$this->_init) { return false; } - $this->_File = null; + unset($this->_File); $this->_clearDirectory($this->_config['path']); @@ -376,8 +371,9 @@ protected function _setKey(string $key, bool $createKey = false): bool if (!$createKey && !$path->isFile()) { return false; } + /** @psalm-suppress TypeDoesNotContainType */ if ( - empty($this->_File) || + !isset($this->_File) || $this->_File->getBasename() !== $key || $this->_File->valid() === false ) { @@ -456,7 +452,7 @@ protected function _key($key): string */ public function clearGroup(string $group): bool { - $this->_File = null; + unset($this->_File); $prefix = (string)$this->_config['prefix']; From 6c462742b435ff480c556d4cc914a8365563ac39 Mon Sep 17 00:00:00 2001 From: mscherer Date: Tue, 1 Feb 2022 01:37:48 +0100 Subject: [PATCH 031/127] Improve docblocks and PHPStan found issues. --- Engine/FileEngine.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Engine/FileEngine.php b/Engine/FileEngine.php index 312aa549a..cce61446e 100644 --- a/Engine/FileEngine.php +++ b/Engine/FileEngine.php @@ -216,6 +216,10 @@ public function delete(string $key): bool return false; } + /** + * @psalm-suppress PossiblyNullReference + * @var string $path + */ $path = $this->_File->getRealPath(); unset($this->_File); From 37997fb3ce2f03d61d8acbb9566ed7d7584229fc Mon Sep 17 00:00:00 2001 From: Mark Story Date: Thu, 24 Feb 2022 11:05:39 -0500 Subject: [PATCH 032/127] Fix deleteMany stopping after the first failure DeleteMany should be more of a best-effort vs stopping at the first missing key. Fixes #16347 --- CacheEngine.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CacheEngine.php b/CacheEngine.php index 8e9fc613a..14006deb5 100644 --- a/CacheEngine.php +++ b/CacheEngine.php @@ -198,14 +198,14 @@ public function deleteMultiple($keys): bool { $this->ensureValidType($keys); + $result = true; foreach ($keys as $key) { - $result = $this->delete($key); - if ($result === false) { - return false; + if (!$this->delete($key)) { + $result = false; } } - return true; + return $result; } /** From a5477023f7bdc2f35d0b9f138a7b8e66a6a13531 Mon Sep 17 00:00:00 2001 From: Mark Story Date: Thu, 24 Feb 2022 22:25:10 -0500 Subject: [PATCH 033/127] Improve API docs for deleteMultiple --- CacheEngine.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CacheEngine.php b/CacheEngine.php index 14006deb5..ed01098e3 100644 --- a/CacheEngine.php +++ b/CacheEngine.php @@ -187,7 +187,11 @@ public function setMultiple($values, $ttl = null): bool } /** - * Deletes multiple cache items in a single operation. + * Deletes multiple cache items as a list + * + * This is a best effort attempt. If deleting an item would + * create an error it will be ignored, and all items will + * be attempted. * * @param iterable $keys A list of string-based keys to be deleted. * @return bool True if the items were successfully removed. False if there was an error. From f42e958842f71c8085ef28f48e9c8a336f47871a Mon Sep 17 00:00:00 2001 From: ADmad Date: Mon, 7 Mar 2022 14:14:08 +0530 Subject: [PATCH 034/127] Use null coalescing assignment. --- Engine/FileEngine.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Engine/FileEngine.php b/Engine/FileEngine.php index cce61446e..70aefb98f 100644 --- a/Engine/FileEngine.php +++ b/Engine/FileEngine.php @@ -89,9 +89,7 @@ public function init(array $config = []): bool { parent::init($config); - if ($this->_config['path'] === null) { - $this->_config['path'] = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'cake_cache' . DIRECTORY_SEPARATOR; - } + $this->_config['path'] ??= sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'cake_cache' . DIRECTORY_SEPARATOR; if (substr($this->_config['path'], -1) !== DIRECTORY_SEPARATOR) { $this->_config['path'] .= DIRECTORY_SEPARATOR; } From 4ba3eaf201d25b5bf0b07ac6609cd2f98ad8b1c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Ram=C5=A1ak?= Date: Fri, 11 Mar 2022 10:38:03 +0100 Subject: [PATCH 035/127] Avoid possible TypeError Exception Exception: unlink(): Argument #1 ($filename) must be of type string, bool given In [/home/wotanabx/webseiten/wow-das/vendor/cakephp/cakephp/src/Cache/Engine/FileEngine.php, line 227] 2022-03-11 02:32:30 error: [TypeError] unlink(): Argument #1 ($filename) must be of type string, bool given in /home/wotanabx/webseiten/wow-das/vendor/cakephp/cakephp/src/Cache/Engine/FileEngine.php on line 227 --- Engine/FileEngine.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Engine/FileEngine.php b/Engine/FileEngine.php index e7ce5ea2c..1d508dd8c 100644 --- a/Engine/FileEngine.php +++ b/Engine/FileEngine.php @@ -222,6 +222,10 @@ public function delete($key): bool /** @psalm-suppress PossiblyNullReference */ $path = $this->_File->getRealPath(); $this->_File = null; + + if ($path === false) { + return false; + } // phpcs:disable return @unlink($path); From 778ed613b26da70cd1f7f208278e1a55f742fdf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Ram=C5=A1ak?= Date: Fri, 11 Mar 2022 11:12:35 +0100 Subject: [PATCH 036/127] removed whitespace on empty line --- Engine/FileEngine.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Engine/FileEngine.php b/Engine/FileEngine.php index 1d508dd8c..46a7f187a 100644 --- a/Engine/FileEngine.php +++ b/Engine/FileEngine.php @@ -222,7 +222,7 @@ public function delete($key): bool /** @psalm-suppress PossiblyNullReference */ $path = $this->_File->getRealPath(); $this->_File = null; - + if ($path === false) { return false; } From b9c2f6865c212e4e2c2ddf4177c00db64e696517 Mon Sep 17 00:00:00 2001 From: ADmad Date: Fri, 11 Mar 2022 23:28:59 +0530 Subject: [PATCH 037/127] Fix errors reported by static analyzers --- Engine/FileEngine.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Engine/FileEngine.php b/Engine/FileEngine.php index b6ddf7a98..b7ba1cd5e 100644 --- a/Engine/FileEngine.php +++ b/Engine/FileEngine.php @@ -216,10 +216,6 @@ public function delete(string $key): bool return false; } - /** - * @psalm-suppress PossiblyNullReference - * @var string $path - */ $path = $this->_File->getRealPath(); unset($this->_File); From bb7a5dcc09713f954e63e12853e46bc7b6690555 Mon Sep 17 00:00:00 2001 From: ADmad Date: Tue, 22 Mar 2022 19:32:24 +0530 Subject: [PATCH 038/127] Update psalm's config. --- Engine/RedisEngine.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Engine/RedisEngine.php b/Engine/RedisEngine.php index 8eac9cbb0..c89e32760 100644 --- a/Engine/RedisEngine.php +++ b/Engine/RedisEngine.php @@ -168,6 +168,7 @@ public function set(string $key, mixed $value, DateInterval|int|null $ttl = null public function get(string $key, mixed $default = null): mixed { $value = $this->_Redis->get($this->_key($key)); + /** @psalm-suppress DocblockTypeContradiction */ if ($value === false) { return $default; } From b4342712701917b2088de873fc02bad5a059f6d4 Mon Sep 17 00:00:00 2001 From: itosho Date: Mon, 2 May 2022 22:45:37 +0900 Subject: [PATCH 039/127] Add deleteAsync and clearBlocking method for improving performance --- Engine/RedisEngine.php | 46 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/Engine/RedisEngine.php b/Engine/RedisEngine.php index b7f0fec4b..63cd66d96 100644 --- a/Engine/RedisEngine.php +++ b/Engine/RedisEngine.php @@ -227,6 +227,21 @@ public function delete($key): bool return $this->_Redis->del($key) > 0; } + /** + * Delete a key from the cache asynchronously + * + * Just unlink a key from the cache. The actual removal will happen later asynchronously. + * + * @param string $key Identifier for the data + * @return bool True if the value was successfully deleted, false if it didn't exist or couldn't be removed + */ + public function deleteAsync(string $key): bool + { + $key = $this->_key($key); + + return $this->_Redis->unlink($key) > 0; + } + /** * Delete all keys from the cache * @@ -256,6 +271,37 @@ public function clear(): bool return $isAllDeleted; } + /** + * Delete all keys from the cache by a blocking operation + * + * Faster than clear() using unlink method. + * + * @return bool True if the cache was successfully cleared, false otherwise + */ + public function clearBlocking(): bool + { + $this->_Redis->setOption(Redis::OPT_SCAN, (string)Redis::SCAN_RETRY); + + $isAllDeleted = true; + $iterator = null; + $pattern = $this->_config['prefix'] . '*'; + + while (true) { + $keys = $this->_Redis->scan($iterator, $pattern); + + if ($keys === false) { + break; + } + + foreach ($keys as $key) { + $isDeleted = ($this->_Redis->unlink($key) > 0); + $isAllDeleted = $isAllDeleted && $isDeleted; + } + } + + return $isAllDeleted; + } + /** * Write data for key into cache if it doesn't exist already. * If it already exists, it fails and returns false. From 6d28fffeba0b9f1c63b8b265864f30a4e1b47f29 Mon Sep 17 00:00:00 2001 From: Corey Taylor Date: Wed, 25 May 2022 17:41:52 -0500 Subject: [PATCH 040/127] Change Cache::remember() callable to closure --- Cache.php | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Cache.php b/Cache.php index a056a0a14..864c2ce47 100644 --- a/Cache.php +++ b/Cache.php @@ -18,6 +18,7 @@ use Cake\Cache\Engine\NullEngine; use Cake\Core\StaticConfigTrait; +use Closure; use RuntimeException; /** @@ -543,8 +544,8 @@ public static function enabled(): bool /** * Provides the ability to easily do read-through caching. * - * When called if the $key is not set in $config, the $callable function - * will be invoked. The results will then be stored into the cache config + * If the key is not set, the default callback is run to get the default value. + * The results will then be stored into the cache config * at key. * * Examples: @@ -558,20 +559,20 @@ public static function enabled(): bool * ``` * * @param string $key The cache key to read/store data at. - * @param callable $callable The callable that provides data in the case when - * the cache key is empty. Can be any callable type supported by your PHP. + * @param \Closure $default The callback that provides data in the case when + * the cache key is empty. * @param string $config The cache configuration to use for this operation. * Defaults to default. * @return mixed If the key is found: the cached data. - * If the key is not found the value returned by the callable. + * If the key is not found the value returned by the the default callback. */ - public static function remember(string $key, callable $callable, string $config = 'default'): mixed + public static function remember(string $key, Closure $default, string $config = 'default'): mixed { $existing = self::read($key, $config); if ($existing !== null) { return $existing; } - $results = $callable(); + $results = $default(); self::write($key, $results, $config); return $results; From 70c5bf50ba349c69bfbbac9c90a4bd3d260dc301 Mon Sep 17 00:00:00 2001 From: Nicos Panayides Date: Wed, 8 Jun 2022 16:08:02 +0300 Subject: [PATCH 041/127] Added count to scan to help speed up cache clear with a large number of keys. Default to 100. --- Engine/RedisEngine.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Engine/RedisEngine.php b/Engine/RedisEngine.php index 63cd66d96..cfb5dd074 100644 --- a/Engine/RedisEngine.php +++ b/Engine/RedisEngine.php @@ -47,6 +47,7 @@ class RedisEngine extends CacheEngine * - `port` port number to the Redis server. * - `prefix` Prefix appended to all entries. Good for when you need to share a keyspace * with either another cache config or another application. + * - `scan_count` Number of keys to ask for each scan (default: 100) * - `server` URL or IP to the Redis server host. * - `timeout` timeout in seconds (float). * - `unix_socket` Path to the unix socket file (default: false) @@ -65,6 +66,7 @@ class RedisEngine extends CacheEngine 'server' => '127.0.0.1', 'timeout' => 0, 'unix_socket' => false, + 'scan_count' => 100, ]; /** @@ -256,7 +258,7 @@ public function clear(): bool $pattern = $this->_config['prefix'] . '*'; while (true) { - $keys = $this->_Redis->scan($iterator, $pattern); + $keys = $this->_Redis->scan($iterator, $pattern, (int)$this->_config['scan_count']); if ($keys === false) { break; @@ -287,7 +289,7 @@ public function clearBlocking(): bool $pattern = $this->_config['prefix'] . '*'; while (true) { - $keys = $this->_Redis->scan($iterator, $pattern); + $keys = $this->_Redis->scan($iterator, $pattern, (int)$this->_config['scan_count']); if ($keys === false) { break; From 9ecfc88a17103df58881a31d54411264e347ac2f Mon Sep 17 00:00:00 2001 From: Nicos Panayides Date: Wed, 8 Jun 2022 17:19:26 +0300 Subject: [PATCH 042/127] Change the default to 10 to match previous behavior --- Engine/RedisEngine.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Engine/RedisEngine.php b/Engine/RedisEngine.php index cfb5dd074..6c4ba8333 100644 --- a/Engine/RedisEngine.php +++ b/Engine/RedisEngine.php @@ -47,7 +47,7 @@ class RedisEngine extends CacheEngine * - `port` port number to the Redis server. * - `prefix` Prefix appended to all entries. Good for when you need to share a keyspace * with either another cache config or another application. - * - `scan_count` Number of keys to ask for each scan (default: 100) + * - `scan_count` Number of keys to ask for each scan (default: 10) * - `server` URL or IP to the Redis server host. * - `timeout` timeout in seconds (float). * - `unix_socket` Path to the unix socket file (default: false) @@ -66,7 +66,7 @@ class RedisEngine extends CacheEngine 'server' => '127.0.0.1', 'timeout' => 0, 'unix_socket' => false, - 'scan_count' => 100, + 'scan_count' => 10, ]; /** From 3b0754763275e522cd72ff63e0c6c279283580ea Mon Sep 17 00:00:00 2001 From: Nicos Panayides Date: Sat, 11 Jun 2022 17:44:35 +0300 Subject: [PATCH 043/127] Rename scan_count option to scanCount --- Engine/RedisEngine.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Engine/RedisEngine.php b/Engine/RedisEngine.php index 6c4ba8333..dc90ef72f 100644 --- a/Engine/RedisEngine.php +++ b/Engine/RedisEngine.php @@ -47,7 +47,7 @@ class RedisEngine extends CacheEngine * - `port` port number to the Redis server. * - `prefix` Prefix appended to all entries. Good for when you need to share a keyspace * with either another cache config or another application. - * - `scan_count` Number of keys to ask for each scan (default: 10) + * - `scanCount` Number of keys to ask for each scan (default: 10) * - `server` URL or IP to the Redis server host. * - `timeout` timeout in seconds (float). * - `unix_socket` Path to the unix socket file (default: false) @@ -66,7 +66,7 @@ class RedisEngine extends CacheEngine 'server' => '127.0.0.1', 'timeout' => 0, 'unix_socket' => false, - 'scan_count' => 10, + 'scanCount' => 10, ]; /** @@ -258,7 +258,7 @@ public function clear(): bool $pattern = $this->_config['prefix'] . '*'; while (true) { - $keys = $this->_Redis->scan($iterator, $pattern, (int)$this->_config['scan_count']); + $keys = $this->_Redis->scan($iterator, $pattern, (int)$this->_config['scanCount']); if ($keys === false) { break; @@ -289,7 +289,7 @@ public function clearBlocking(): bool $pattern = $this->_config['prefix'] . '*'; while (true) { - $keys = $this->_Redis->scan($iterator, $pattern, (int)$this->_config['scan_count']); + $keys = $this->_Redis->scan($iterator, $pattern, (int)$this->_config['scanCount']); if ($keys === false) { break; From cd8af4a5f214413607e2eca2188a25bc2f7e3f61 Mon Sep 17 00:00:00 2001 From: Erwane Breton Date: Mon, 13 Jun 2022 13:51:02 +0200 Subject: [PATCH 044/127] Allow the 'P1D' notation for DateInterval cache ttl. --- CacheEngine.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CacheEngine.php b/CacheEngine.php index ed01098e3..da5bcc719 100644 --- a/CacheEngine.php +++ b/CacheEngine.php @@ -18,6 +18,7 @@ use Cake\Core\InstanceConfigTrait; use DateInterval; +use DateTime; use Psr\SimpleCache\CacheInterface; /** @@ -383,7 +384,9 @@ protected function duration($ttl): int return $ttl; } if ($ttl instanceof DateInterval) { - return (int)$ttl->format('%s'); + return (int)DateTime::createFromFormat('U', '0') + ->add($ttl) + ->format('U'); } throw new InvalidArgumentException('TTL values must be one of null, int, \DateInterval'); From b293100555c667377f926a4f4620d41323be930e Mon Sep 17 00:00:00 2001 From: ADmad Date: Thu, 16 Jun 2022 13:19:34 +0530 Subject: [PATCH 045/127] Fix CS error --- CacheEngine.php | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/CacheEngine.php b/CacheEngine.php index 4a23821f1..0498cb675 100644 --- a/CacheEngine.php +++ b/CacheEngine.php @@ -376,12 +376,9 @@ protected function duration(DateInterval|int|null $ttl): int if (is_int($ttl)) { return $ttl; } - if ($ttl instanceof DateInterval) { - return (int)DateTime::createFromFormat('U', '0') - ->add($ttl) - ->format('U'); - } - return (int)$ttl->format('%s'); + return (int)DateTime::createFromFormat('U', '0') + ->add($ttl) + ->format('U'); } } From 2350b2a78631fd63d84fe5a47bb5eb60c65d0852 Mon Sep 17 00:00:00 2001 From: Corey Taylor Date: Wed, 22 Jun 2022 23:22:14 -0500 Subject: [PATCH 046/127] Use class-string directly in annotations --- CacheRegistry.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CacheRegistry.php b/CacheRegistry.php index 883e09318..112c8893f 100644 --- a/CacheRegistry.php +++ b/CacheRegistry.php @@ -36,11 +36,11 @@ class CacheRegistry extends ObjectRegistry * Part of the template method for Cake\Core\ObjectRegistry::load() * * @param string $class Partial classname to resolve. - * @return string|null Either the correct classname or null. - * @psalm-return class-string|null + * @return class-string<\Cake\Cache\CacheEngine>|null Either the correct classname or null. */ protected function _resolveClassName(string $class): ?string { + /** @var class-string<\Cake\Cache\CacheEngine>|null */ return App::className($class, 'Cache/Engine', 'Engine'); } From e7d267a78c1aec48acc2f25fd43dd81c43ea0c73 Mon Sep 17 00:00:00 2001 From: ADmad Date: Wed, 29 Jun 2022 01:51:37 +0530 Subject: [PATCH 047/127] Add intersection types. (#16587) * Add intersection types. Also use short nullable type. * Ignore psalm failure. It currently doesn't support intersection types. --- Cache.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Cache.php b/Cache.php index 864c2ce47..ea7ce1423 100644 --- a/Cache.php +++ b/Cache.php @@ -19,6 +19,7 @@ use Cake\Cache\Engine\NullEngine; use Cake\Core\StaticConfigTrait; use Closure; +use Psr\SimpleCache\CacheInterface; use RuntimeException; /** @@ -201,7 +202,7 @@ protected static function _buildEngine(string $name): void * @param string $config The name of the configured cache backend. * @return \Psr\SimpleCache\CacheInterface&\Cake\Cache\CacheEngineInterface */ - public static function pool(string $config) + public static function pool(string $config): CacheInterface&CacheEngineInterface { if (!static::$_enabled) { return new NullEngine(); From 7afb81d9347f118050b483427bbdde1f6f6d49f6 Mon Sep 17 00:00:00 2001 From: ADmad Date: Wed, 29 Jun 2022 13:28:06 +0530 Subject: [PATCH 048/127] Update PHP version constraint in split packages. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 16e0b7d80..a1783006c 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ "source": "https://github.com/cakephp/cache" }, "require": { - "php": ">=8.0", + "php": ">=8.1", "cakephp/core": "^5.0", "psr/simple-cache": "^2.0 || ^3.0" }, From b72f12de5bd74c5c7ce3f9dfd40a116b9c265243 Mon Sep 17 00:00:00 2001 From: Corey Taylor Date: Sat, 9 Jul 2022 01:09:06 -0500 Subject: [PATCH 049/127] Replace RuntimeException with CakeException, DatabaseException or InvalidArgumentException --- CacheRegistry.php | 8 ++++---- Engine/ApcuEngine.php | 4 ++-- Engine/MemcachedEngine.php | 4 ++-- Engine/RedisEngine.php | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/CacheRegistry.php b/CacheRegistry.php index 112c8893f..6c5b7ada6 100644 --- a/CacheRegistry.php +++ b/CacheRegistry.php @@ -18,8 +18,8 @@ use BadMethodCallException; use Cake\Core\App; +use Cake\Core\Exception\CakeException; use Cake\Core\ObjectRegistry; -use RuntimeException; /** * An object registry for cache engines. @@ -68,7 +68,7 @@ protected function _throwMissingClassError(string $class, ?string $plugin): void * @param string $alias The alias of the object. * @param array $config An array of settings to use for the cache engine. * @return \Cake\Cache\CacheEngine The constructed CacheEngine class. - * @throws \RuntimeException when an object doesn't implement the correct interface. + * @throws \Cake\Core\Exception\CakeException when an object doesn't implement the correct interface. */ protected function _create(object|string $class, string $alias, array $config): CacheEngine { @@ -80,13 +80,13 @@ protected function _create(object|string $class, string $alias, array $config): unset($config['className']); if (!($instance instanceof CacheEngine)) { - throw new RuntimeException( + throw new CakeException( 'Cache engines must use Cake\Cache\CacheEngine as a base class.' ); } if (!$instance->init($config)) { - throw new RuntimeException( + throw new CakeException( sprintf( 'Cache engine %s is not properly configured. Check error log for additional information.', get_class($instance) diff --git a/Engine/ApcuEngine.php b/Engine/ApcuEngine.php index cd7753f34..ecd6ed3fe 100644 --- a/Engine/ApcuEngine.php +++ b/Engine/ApcuEngine.php @@ -18,8 +18,8 @@ use APCUIterator; use Cake\Cache\CacheEngine; +use Cake\Core\Exception\CakeException; use DateInterval; -use RuntimeException; /** * APCu storage engine for cache @@ -45,7 +45,7 @@ class ApcuEngine extends CacheEngine public function init(array $config = []): bool { if (!extension_loaded('apcu')) { - throw new RuntimeException('The `apcu` extension must be enabled to use ApcuEngine.'); + throw new CakeException('The `apcu` extension must be enabled to use ApcuEngine.'); } return parent::init($config); diff --git a/Engine/MemcachedEngine.php b/Engine/MemcachedEngine.php index f14ecc636..b7157bf9b 100644 --- a/Engine/MemcachedEngine.php +++ b/Engine/MemcachedEngine.php @@ -17,10 +17,10 @@ namespace Cake\Cache\Engine; use Cake\Cache\CacheEngine; +use Cake\Core\Exception\CakeException; use DateInterval; use InvalidArgumentException; use Memcached; -use RuntimeException; /** * Memcached storage engine for cache. Memcached has some limitations in the amount of @@ -105,7 +105,7 @@ class MemcachedEngine extends CacheEngine public function init(array $config = []): bool { if (!extension_loaded('memcached')) { - throw new RuntimeException('The `memcached` extension must be enabled to use MemcachedEngine.'); + throw new CakeException('The `memcached` extension must be enabled to use MemcachedEngine.'); } $this->_serializers = [ diff --git a/Engine/RedisEngine.php b/Engine/RedisEngine.php index fe78f33be..c0c830d0a 100644 --- a/Engine/RedisEngine.php +++ b/Engine/RedisEngine.php @@ -18,11 +18,11 @@ namespace Cake\Cache\Engine; use Cake\Cache\CacheEngine; +use Cake\Core\Exception\CakeException; use Cake\Log\Log; use DateInterval; use Redis; use RedisException; -use RuntimeException; /** * Redis storage engine for cache. @@ -81,7 +81,7 @@ class RedisEngine extends CacheEngine public function init(array $config = []): bool { if (!extension_loaded('redis')) { - throw new RuntimeException('The `redis` extension must be enabled to use RedisEngine.'); + throw new CakeException('The `redis` extension must be enabled to use RedisEngine.'); } if (!empty($config['host'])) { From 2e57d69b2478ab880c4ca833344c55526e81273c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgaras=20Janu=C5=A1auskas?= Date: Mon, 11 Jul 2022 13:51:09 +0300 Subject: [PATCH 050/127] Allow special symbols in cache key using FileEngine --- Engine/FileEngine.php | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/Engine/FileEngine.php b/Engine/FileEngine.php index 46a7f187a..e9c9cd644 100644 --- a/Engine/FileEngine.php +++ b/Engine/FileEngine.php @@ -17,7 +17,6 @@ namespace Cake\Cache\Engine; use Cake\Cache\CacheEngine; -use Cake\Cache\InvalidArgumentException; use CallbackFilterIterator; use Exception; use FilesystemIterator; @@ -441,14 +440,7 @@ protected function _key($key): string { $key = parent::_key($key); - if (preg_match('/[\/\\<>?:|*"]/', $key)) { - throw new InvalidArgumentException( - "Cache key `{$key}` contains invalid characters. " . - 'You cannot use /, \\, <, >, ?, :, |, *, or " in cache keys.' - ); - } - - return $key; + return rawurlencode($key); } /** From 56228b0355b667c6ae45af36bea35a852bf7f739 Mon Sep 17 00:00:00 2001 From: ADmad Date: Sat, 16 Jul 2022 14:12:09 +0530 Subject: [PATCH 051/127] Use assert() for asserting valid class types. This allows the assertion code to be totally skipped in production using the zend.assertions ini config. --- CacheRegistry.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/CacheRegistry.php b/CacheRegistry.php index 6c5b7ada6..eb94b6049 100644 --- a/CacheRegistry.php +++ b/CacheRegistry.php @@ -79,11 +79,7 @@ protected function _create(object|string $class, string $alias, array $config): } unset($config['className']); - if (!($instance instanceof CacheEngine)) { - throw new CakeException( - 'Cache engines must use Cake\Cache\CacheEngine as a base class.' - ); - } + assert($instance instanceof CacheEngine, 'Cache engines must extend Cake\Cache\CacheEngine.'); if (!$instance->init($config)) { throw new CakeException( From d98447bdd350c43cefdd5785a2e8b5e10c6e251f Mon Sep 17 00:00:00 2001 From: ADmad Date: Fri, 22 Jul 2022 19:22:47 +0530 Subject: [PATCH 052/127] Update docblocks. --- CacheRegistry.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CacheRegistry.php b/CacheRegistry.php index eb94b6049..672c61c5b 100644 --- a/CacheRegistry.php +++ b/CacheRegistry.php @@ -68,7 +68,7 @@ protected function _throwMissingClassError(string $class, ?string $plugin): void * @param string $alias The alias of the object. * @param array $config An array of settings to use for the cache engine. * @return \Cake\Cache\CacheEngine The constructed CacheEngine class. - * @throws \Cake\Core\Exception\CakeException when an object doesn't implement the correct interface. + * @throws \Cake\Core\Exception\CakeException When the cache engine cannot be initialized. */ protected function _create(object|string $class, string $alias, array $config): CacheEngine { From ff797927c67b44bd94e22d06608c8f064a2703d7 Mon Sep 17 00:00:00 2001 From: Kevin Pfeifer Date: Wed, 3 Aug 2022 22:05:12 +0200 Subject: [PATCH 053/127] use new str_ methods --- Engine/MemcachedEngine.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Engine/MemcachedEngine.php b/Engine/MemcachedEngine.php index b7157bf9b..c620f6689 100644 --- a/Engine/MemcachedEngine.php +++ b/Engine/MemcachedEngine.php @@ -262,7 +262,7 @@ public function parseServerString(string $server): array if (str_starts_with($server, $socketTransport)) { return [substr($server, strlen($socketTransport)), 0]; } - if (substr($server, 0, 1) === '[') { + if (str_starts_with($server, '[')) { $position = strpos($server, ']:'); if ($position !== false) { $position++; From 078e5568ce3d0586f66aacae813f67943d091920 Mon Sep 17 00:00:00 2001 From: Mark Scherer Date: Wed, 17 Aug 2022 12:21:45 +0200 Subject: [PATCH 054/127] Fix up assoc docblocks. (#16689) Fix up assoc docblocks. Co-authored-by: ADmad --- Engine/ArrayEngine.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Engine/ArrayEngine.php b/Engine/ArrayEngine.php index 9050537eb..4693c0242 100644 --- a/Engine/ArrayEngine.php +++ b/Engine/ArrayEngine.php @@ -35,7 +35,7 @@ class ArrayEngine extends CacheEngine * * Structured as [key => [exp => expiration, val => value]] * - * @var array + * @var array */ protected $data = []; From 093eb71397ba8bfdc34e98aa20b0017504c3f24e Mon Sep 17 00:00:00 2001 From: Kevin Pfeifer Date: Thu, 15 Sep 2022 17:44:28 +0200 Subject: [PATCH 055/127] unify exception string building --- Cache.php | 4 ++-- CacheRegistry.php | 2 +- Engine/MemcachedEngine.php | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cache.php b/Cache.php index ea7ce1423..e57d87aba 100644 --- a/Cache.php +++ b/Cache.php @@ -168,7 +168,7 @@ protected static function _buildEngine(string $name): void if ($config['fallback'] === $name) { throw new InvalidArgumentException(sprintf( - '"%s" cache configuration cannot fallback to itself.', + '`%s` cache configuration cannot fallback to itself.', $name ), 0, $e); } @@ -505,7 +505,7 @@ public static function groupConfigs(?string $group = null): array return [$group => self::$_groups[$group]]; } - throw new InvalidArgumentException(sprintf('Invalid cache group %s', $group)); + throw new InvalidArgumentException(sprintf('Invalid cache group `%s`.', $group)); } /** diff --git a/CacheRegistry.php b/CacheRegistry.php index 672c61c5b..4132d593d 100644 --- a/CacheRegistry.php +++ b/CacheRegistry.php @@ -56,7 +56,7 @@ protected function _resolveClassName(string $class): ?string */ protected function _throwMissingClassError(string $class, ?string $plugin): void { - throw new BadMethodCallException(sprintf('Cache engine %s is not available.', $class)); + throw new BadMethodCallException(sprintf('Cache engine `%s` is not available.', $class)); } /** diff --git a/Engine/MemcachedEngine.php b/Engine/MemcachedEngine.php index c620f6689..fcdc1d5bb 100644 --- a/Engine/MemcachedEngine.php +++ b/Engine/MemcachedEngine.php @@ -214,7 +214,7 @@ protected function _setOptions(): void $serializer = strtolower($this->_config['serialize']); if (!isset($this->_serializers[$serializer])) { throw new InvalidArgumentException( - sprintf('%s is not a valid serializer engine for Memcached', $serializer) + sprintf('`%s` is not a valid serializer engine for Memcached.', $serializer) ); } @@ -223,7 +223,7 @@ protected function _setOptions(): void !constant('Memcached::HAVE_' . strtoupper($serializer)) ) { throw new InvalidArgumentException( - sprintf('Memcached extension is not compiled with %s support', $serializer) + sprintf('Memcached extension is not compiled with `%s` support.', $serializer) ); } From 83c7fcdf7b9d840f10e4f87cdda37d4a5b2eec1e Mon Sep 17 00:00:00 2001 From: ADmad Date: Mon, 19 Sep 2022 08:35:26 +0530 Subject: [PATCH 056/127] Fix errors reported by phpstan. --- Engine/MemcachedEngine.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Engine/MemcachedEngine.php b/Engine/MemcachedEngine.php index fcdc1d5bb..7a0813277 100644 --- a/Engine/MemcachedEngine.php +++ b/Engine/MemcachedEngine.php @@ -237,10 +237,8 @@ protected function _setOptions(): void defined('Memcached::OPT_CLIENT_MODE') && defined('Memcached::DYNAMIC_CLIENT_MODE') ) { - $this->_Memcached->setOption( - Memcached::OPT_CLIENT_MODE, - Memcached::DYNAMIC_CLIENT_MODE - ); + /** @phpstan-ignore-next-line */ + $this->_Memcached->setOption(Memcached::OPT_CLIENT_MODE, Memcached::DYNAMIC_CLIENT_MODE); } $this->_Memcached->setOption( From 579c15924adba643b6531b1a6a72dfd557f23d7b Mon Sep 17 00:00:00 2001 From: ADmad Date: Mon, 19 Sep 2022 11:13:11 +0530 Subject: [PATCH 057/127] Add missing type declarations. --- Engine/FileEngine.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Engine/FileEngine.php b/Engine/FileEngine.php index 80ff4de05..28c51be1d 100644 --- a/Engine/FileEngine.php +++ b/Engine/FileEngine.php @@ -431,7 +431,7 @@ protected function _active(): bool /** * @inheritDoc */ - protected function _key($key): string + protected function _key(string $key): string { $key = parent::_key($key); From 8100b52cbdce7d8bab4a6de7f179f91bf63c18ca Mon Sep 17 00:00:00 2001 From: ADmad Date: Mon, 26 Sep 2022 13:04:49 +0530 Subject: [PATCH 058/127] Use ::class instead of get_class(). --- Cache.php | 2 +- CacheRegistry.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cache.php b/Cache.php index e57d87aba..03911daa9 100644 --- a/Cache.php +++ b/Cache.php @@ -255,7 +255,7 @@ public static function write(string $key, mixed $value, string $config = 'defaul "%s cache was unable to write '%s' to %s cache", $config, $key, - get_class($backend) + $backend::class ), E_USER_WARNING ); diff --git a/CacheRegistry.php b/CacheRegistry.php index 4132d593d..9734e003e 100644 --- a/CacheRegistry.php +++ b/CacheRegistry.php @@ -85,7 +85,7 @@ protected function _create(object|string $class, string $alias, array $config): throw new CakeException( sprintf( 'Cache engine %s is not properly configured. Check error log for additional information.', - get_class($instance) + $instance::class ) ); } From 79e447eb67f4e9038ad695c0b3b97f9b73653777 Mon Sep 17 00:00:00 2001 From: ADmad Date: Thu, 6 Oct 2022 02:19:15 +0530 Subject: [PATCH 059/127] Use null coalescing assignment. --- Cache.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Cache.php b/Cache.php index 03911daa9..0180b19be 100644 --- a/Cache.php +++ b/Cache.php @@ -111,11 +111,7 @@ class Cache */ public static function getRegistry(): CacheRegistry { - if (isset(static::$_registry)) { - return static::$_registry; - } - - return static::$_registry = new CacheRegistry(); + return static::$_registry ??= new CacheRegistry(); } /** From 7bd71a2d7cd171b42638686197ab9ca98f16fa5b Mon Sep 17 00:00:00 2001 From: ADmad Date: Fri, 7 Oct 2022 22:10:13 +0530 Subject: [PATCH 060/127] Update psalm --- Engine/FileEngine.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Engine/FileEngine.php b/Engine/FileEngine.php index e9c9cd644..35252b98e 100644 --- a/Engine/FileEngine.php +++ b/Engine/FileEngine.php @@ -172,6 +172,7 @@ public function get($key, $default = null) /** @psalm-suppress PossiblyNullReference */ $this->_File->rewind(); $time = time(); + /** @psalm-suppress RiskyCast */ $cachetime = (int)$this->_File->current(); if ($cachetime < $time) { From 0b45092175b589f543b2c024df67fd107c1d78b1 Mon Sep 17 00:00:00 2001 From: ADmad Date: Sat, 8 Oct 2022 02:35:58 +0530 Subject: [PATCH 061/127] Remove unused psalm error suppression --- Engine/FileEngine.php | 1 - 1 file changed, 1 deletion(-) diff --git a/Engine/FileEngine.php b/Engine/FileEngine.php index 357668817..28c51be1d 100644 --- a/Engine/FileEngine.php +++ b/Engine/FileEngine.php @@ -167,7 +167,6 @@ public function get(string $key, mixed $default = null): mixed $this->_File->rewind(); $time = time(); - /** @psalm-suppress RiskyCast */ $cachetime = (int)$this->_File->current(); if ($cachetime < $time) { From 8ecd6bf3608da948a71378fd3ffa5731bd4902e4 Mon Sep 17 00:00:00 2001 From: Mark Story Date: Fri, 7 Oct 2022 14:30:43 -0700 Subject: [PATCH 062/127] Start to replace `@var` with assert() While `@var` annotations are good for convincing static analyzers of types, we could still encounter runtime warnings. Using assert() will convert those warnings/notices into exceptions. If folks like this approach I can apply it to the remaining classes in managable chunks. --- Cache.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Cache.php b/Cache.php index 03911daa9..235cf717a 100644 --- a/Cache.php +++ b/Cache.php @@ -151,6 +151,7 @@ protected static function _buildEngine(string $name): void /** @var array $config */ $config = static::$_config[$name]; + assert(is_array($config)); try { $registry->load($name, $config); From 2cd7c708b39ca0419407be9ef1c9b8eb7de06a22 Mon Sep 17 00:00:00 2001 From: Mark Story Date: Sat, 8 Oct 2022 00:14:28 -0400 Subject: [PATCH 063/127] Remove type comment. --- Cache.php | 1 - 1 file changed, 1 deletion(-) diff --git a/Cache.php b/Cache.php index 235cf717a..f559ff95c 100644 --- a/Cache.php +++ b/Cache.php @@ -149,7 +149,6 @@ protected static function _buildEngine(string $name): void ); } - /** @var array $config */ $config = static::$_config[$name]; assert(is_array($config)); From 1735c5479b65da9d32a0d7208f760b951fb6545b Mon Sep 17 00:00:00 2001 From: Mark Story Date: Sun, 9 Oct 2022 16:51:59 -0400 Subject: [PATCH 064/127] 5.x Update remaining var annotation to use assert() There are still a bunch of `@var` annotations left, but they are for types more complex than PHP's typesystem can currently handle or were inline hints for factory methods. --- Cache.php | 3 ++- Engine/FileEngine.php | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Cache.php b/Cache.php index 9cdca9a1e..e7e6de024 100644 --- a/Cache.php +++ b/Cache.php @@ -169,8 +169,9 @@ protected static function _buildEngine(string $name): void ), 0, $e); } - /** @var \Cake\Cache\CacheEngine $fallbackEngine */ $fallbackEngine = clone static::pool($config['fallback']); + assert($fallbackEngine instanceof CacheEngine); + $newConfig = $config + ['groups' => [], 'prefix' => null]; $fallbackEngine->setConfig('groups', $newConfig['groups'], false); if ($newConfig['prefix']) { diff --git a/Engine/FileEngine.php b/Engine/FileEngine.php index 28c51be1d..87dd1a5b9 100644 --- a/Engine/FileEngine.php +++ b/Engine/FileEngine.php @@ -248,8 +248,8 @@ public function clear(): bool RecursiveIteratorIterator::SELF_FIRST ); $cleared = []; - /** @var \SplFileInfo $fileInfo */ foreach ($contents as $fileInfo) { + assert($fileInfo instanceof SplFileInfo); if ($fileInfo->isFile()) { unset($fileInfo); continue; From 7dbd415a0fbeebf09a9f1981c36d7a40c75079bd Mon Sep 17 00:00:00 2001 From: ADmad Date: Tue, 11 Oct 2022 00:45:19 +0530 Subject: [PATCH 065/127] Improve type annotations. --- CacheRegistry.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CacheRegistry.php b/CacheRegistry.php index 9734e003e..2d5d9d02f 100644 --- a/CacheRegistry.php +++ b/CacheRegistry.php @@ -64,7 +64,7 @@ protected function _throwMissingClassError(string $class, ?string $plugin): void * * Part of the template method for Cake\Core\ObjectRegistry::load() * - * @param \Cake\Cache\CacheEngine|string $class The classname or object to make. + * @param \Cake\Cache\CacheEngine|class-string<\Cake\Cache\CacheEngine> $class The classname or object to make. * @param string $alias The alias of the object. * @param array $config An array of settings to use for the cache engine. * @return \Cake\Cache\CacheEngine The constructed CacheEngine class. From 68ce92100547beefa33454ea3997b8f6f36fc219 Mon Sep 17 00:00:00 2001 From: Mark Story Date: Mon, 10 Oct 2022 11:41:27 -0400 Subject: [PATCH 066/127] Reduce assert() usage We don't need to assert() types when we'll also check types on return values. Coercing filesystem iterators helps reduce overhead of type checks as well. --- Engine/FileEngine.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Engine/FileEngine.php b/Engine/FileEngine.php index 87dd1a5b9..2ef1fb9ed 100644 --- a/Engine/FileEngine.php +++ b/Engine/FileEngine.php @@ -243,13 +243,13 @@ public function clear(): bool $this->_config['path'], FilesystemIterator::SKIP_DOTS ); + /** @var \RecursiveDirectoryIterator $contents Coerce for phpstan/psalm */ $contents = new RecursiveIteratorIterator( $directory, RecursiveIteratorIterator::SELF_FIRST ); $cleared = []; foreach ($contents as $fileInfo) { - assert($fileInfo instanceof SplFileInfo); if ($fileInfo->isFile()) { unset($fileInfo); continue; From 20d44762af4f797f1f7ebfbd5eba8141677ac43e Mon Sep 17 00:00:00 2001 From: ADmad Date: Sun, 6 Nov 2022 12:51:51 +0530 Subject: [PATCH 067/127] Fix stan and CS errors --- Engine/MemcachedEngine.php | 1 - 1 file changed, 1 deletion(-) diff --git a/Engine/MemcachedEngine.php b/Engine/MemcachedEngine.php index 7a0813277..669816a4a 100644 --- a/Engine/MemcachedEngine.php +++ b/Engine/MemcachedEngine.php @@ -237,7 +237,6 @@ protected function _setOptions(): void defined('Memcached::OPT_CLIENT_MODE') && defined('Memcached::DYNAMIC_CLIENT_MODE') ) { - /** @phpstan-ignore-next-line */ $this->_Memcached->setOption(Memcached::OPT_CLIENT_MODE, Memcached::DYNAMIC_CLIENT_MODE); } From 663f44bf03d39a8314ac52c66c64fada1e50cc80 Mon Sep 17 00:00:00 2001 From: ADmad Date: Fri, 2 Dec 2022 19:26:21 +0530 Subject: [PATCH 068/127] Fix errors reported by psalm. --- Engine/RedisEngine.php | 1 - 1 file changed, 1 deletion(-) diff --git a/Engine/RedisEngine.php b/Engine/RedisEngine.php index c0c830d0a..9e9768253 100644 --- a/Engine/RedisEngine.php +++ b/Engine/RedisEngine.php @@ -170,7 +170,6 @@ public function set(string $key, mixed $value, DateInterval|int|null $ttl = null public function get(string $key, mixed $default = null): mixed { $value = $this->_Redis->get($this->_key($key)); - /** @psalm-suppress DocblockTypeContradiction */ if ($value === false) { return $default; } From 839596fe729afd1d28bfb0f06e643032caacaa55 Mon Sep 17 00:00:00 2001 From: mscherer Date: Sat, 7 Jan 2023 04:32:36 +0100 Subject: [PATCH 069/127] Fix up TypeError cases found by PHPStan level 7/8 --- Engine/FileEngine.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Engine/FileEngine.php b/Engine/FileEngine.php index 2ef1fb9ed..1966ca0d0 100644 --- a/Engine/FileEngine.php +++ b/Engine/FileEngine.php @@ -243,7 +243,7 @@ public function clear(): bool $this->_config['path'], FilesystemIterator::SKIP_DOTS ); - /** @var \RecursiveDirectoryIterator $contents Coerce for phpstan/psalm */ + /** @var \RecursiveDirectoryIterator<\SplFileInfo> $contents Coerce for phpstan/psalm */ $contents = new RecursiveIteratorIterator( $directory, RecursiveIteratorIterator::SELF_FIRST From 95b9f88aa3550a6207d88f3a7e08714fd204a2f6 Mon Sep 17 00:00:00 2001 From: mscherer Date: Sat, 7 Jan 2023 14:29:00 +0100 Subject: [PATCH 070/127] Fix up Psalm. --- Engine/FileEngine.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Engine/FileEngine.php b/Engine/FileEngine.php index 1966ca0d0..e77d011fe 100644 --- a/Engine/FileEngine.php +++ b/Engine/FileEngine.php @@ -243,13 +243,13 @@ public function clear(): bool $this->_config['path'], FilesystemIterator::SKIP_DOTS ); - /** @var \RecursiveDirectoryIterator<\SplFileInfo> $contents Coerce for phpstan/psalm */ - $contents = new RecursiveIteratorIterator( + /** @var \RecursiveDirectoryIterator<\SplFileInfo> $iterator Coerce for phpstan/psalm */ + $iterator = new RecursiveIteratorIterator( $directory, RecursiveIteratorIterator::SELF_FIRST ); $cleared = []; - foreach ($contents as $fileInfo) { + foreach ($iterator as $fileInfo) { if ($fileInfo->isFile()) { unset($fileInfo); continue; @@ -273,7 +273,7 @@ public function clear(): bool // unsetting iterators helps releasing possible locks in certain environments, // which could otherwise make `rmdir()` fail - unset($directory, $contents); + unset($directory, $iterator); return true; } From 8e3c9af39afe5bb5114a871a4d71781c48edb80f Mon Sep 17 00:00:00 2001 From: mscherer Date: Tue, 10 Jan 2023 15:42:23 +0100 Subject: [PATCH 071/127] Fix up TypeError cases found by PHPStan level 7/8 --- Cache.php | 8 ++++---- CacheEngine.php | 7 +++++-- CacheRegistry.php | 2 +- Engine/MemcachedEngine.php | 2 +- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Cache.php b/Cache.php index e7e6de024..635bd1ab8 100644 --- a/Cache.php +++ b/Cache.php @@ -141,12 +141,11 @@ protected static function _buildEngine(string $name): void if (empty(static::$_config[$name]['className'])) { throw new InvalidArgumentException( - sprintf('The "%s" cache configuration does not exist.', $name) + sprintf('The `%s` cache configuration does not exist.', $name) ); } $config = static::$_config[$name]; - assert(is_array($config)); try { $registry->load($name, $config); @@ -185,6 +184,7 @@ protected static function _buildEngine(string $name): void } if (!empty($config['groups'])) { + /** @var string $group */ foreach ($config['groups'] as $group) { static::$_groups[$group][] = $name; static::$_groups[$group] = array_unique(static::$_groups[$group]); @@ -356,7 +356,7 @@ public static function readMany(iterable $keys, string $config = 'default'): ite public static function increment(string $key, int $offset = 1, string $config = 'default'): int|false { if ($offset < 0) { - throw new InvalidArgumentException('Offset cannot be less than 0.'); + throw new InvalidArgumentException('Offset cannot be less than `0`.'); } return static::pool($config)->increment($key, $offset); @@ -375,7 +375,7 @@ public static function increment(string $key, int $offset = 1, string $config = public static function decrement(string $key, int $offset = 1, string $config = 'default'): int|false { if ($offset < 0) { - throw new InvalidArgumentException('Offset cannot be less than 0.'); + throw new InvalidArgumentException('Offset cannot be less than `0`.'); } return static::pool($config)->decrement($key, $offset); diff --git a/CacheEngine.php b/CacheEngine.php index 0498cb675..ea0ab384b 100644 --- a/CacheEngine.php +++ b/CacheEngine.php @@ -127,7 +127,7 @@ protected function ensureValidType(iterable $iterable, string $check = self::CHE /** * Obtains multiple cache items by their unique keys. * - * @param iterable $keys A list of keys that can obtained in a single operation. + * @param iterable $keys A list of keys that can obtained in a single operation. * @param mixed $default Default value to return for keys that do not exist. * @return iterable A list of key value pairs. Cache keys that do not exist or are stale will have $default as value. * @throws \Cake\Cache\InvalidArgumentException If $keys is neither an array nor a Traversable, @@ -377,7 +377,10 @@ protected function duration(DateInterval|int|null $ttl): int return $ttl; } - return (int)DateTime::createFromFormat('U', '0') + /** @var \DateTime $datetime */ + $datetime = DateTime::createFromFormat('U', '0'); + + return (int)$datetime ->add($ttl) ->format('U'); } diff --git a/CacheRegistry.php b/CacheRegistry.php index 2d5d9d02f..635043703 100644 --- a/CacheRegistry.php +++ b/CacheRegistry.php @@ -79,7 +79,7 @@ protected function _create(object|string $class, string $alias, array $config): } unset($config['className']); - assert($instance instanceof CacheEngine, 'Cache engines must extend Cake\Cache\CacheEngine.'); + assert($instance instanceof CacheEngine, 'Cache engines must extend `' . CacheEngine::class . '`.'); if (!$instance->init($config)) { throw new CakeException( diff --git a/Engine/MemcachedEngine.php b/Engine/MemcachedEngine.php index 669816a4a..8d3ce8d76 100644 --- a/Engine/MemcachedEngine.php +++ b/Engine/MemcachedEngine.php @@ -352,7 +352,7 @@ public function get(string $key, mixed $default = null): mixed /** * Read many keys from the cache at once * - * @param iterable $keys An array of identifiers for the data + * @param iterable $keys An array of identifiers for the data * @param mixed $default Default value to return for keys that do not exist. * @return iterable An array containing, for each of the given $keys, the cached data or * false if cached data could not be retrieved. From 5a01c155c5273b2bcca8637ed0eba2d0d1fdb55a Mon Sep 17 00:00:00 2001 From: Mark Scherer Date: Sat, 14 Jan 2023 03:53:24 +0100 Subject: [PATCH 072/127] Consolidate code fencing in exception messages. (#16956) Consolidate code fencing in exception messages. --- Cache.php | 2 +- CacheRegistry.php | 2 +- Engine/ApcuEngine.php | 2 +- Engine/FileEngine.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cache.php b/Cache.php index 635bd1ab8..2ae96caf4 100644 --- a/Cache.php +++ b/Cache.php @@ -249,7 +249,7 @@ public static function write(string $key, mixed $value, string $config = 'defaul if ($success === false && $value !== '') { trigger_error( sprintf( - "%s cache was unable to write '%s' to %s cache", + '%s cache was unable to write `%s` to `%s` cache', $config, $key, $backend::class diff --git a/CacheRegistry.php b/CacheRegistry.php index 635043703..564a0040f 100644 --- a/CacheRegistry.php +++ b/CacheRegistry.php @@ -84,7 +84,7 @@ protected function _create(object|string $class, string $alias, array $config): if (!$instance->init($config)) { throw new CakeException( sprintf( - 'Cache engine %s is not properly configured. Check error log for additional information.', + 'Cache engine `%s` is not properly configured. Check error log for additional information.', $instance::class ) ); diff --git a/Engine/ApcuEngine.php b/Engine/ApcuEngine.php index ecd6ed3fe..beb68f5bb 100644 --- a/Engine/ApcuEngine.php +++ b/Engine/ApcuEngine.php @@ -204,7 +204,7 @@ public function groups(): array $value = 1; if (apcu_store($group, $value) === false) { $this->warning( - sprintf('Failed to store key "%s" with value "%s" into APCu cache.', $group, $value) + sprintf('Failed to store key `%s` with value `%s` into APCu cache.', $group, $value) ); } $groups[$group] = $value; diff --git a/Engine/FileEngine.php b/Engine/FileEngine.php index e77d011fe..bd091b615 100644 --- a/Engine/FileEngine.php +++ b/Engine/FileEngine.php @@ -390,7 +390,7 @@ protected function _setKey(string $key, bool $createKey = false): bool if (!$exists && !chmod($this->_File->getPathname(), (int)$this->_config['mask'])) { trigger_error(sprintf( - 'Could not apply permission mask "%s" on cache file "%s"', + 'Could not apply permission mask `%s` on cache file `%s`', $this->_File->getPathname(), $this->_config['mask'] ), E_USER_WARNING); From bf4ab67dad8b5f66afa8fc98f2d5af9b068c1548 Mon Sep 17 00:00:00 2001 From: Brian French Date: Sat, 25 Feb 2023 15:00:46 -0500 Subject: [PATCH 073/127] Throw an Exception instead of an error on Cache::write() fail. See original #16932 (#17034) Throw a CacheWriteException when a Cache::write() fails, instead of triggering an error. This allows the developer more control over how to handle a Cache::write() issue. --- Cache.php | 31 ++++++++++++----------- CacheEngine.php | 19 +++++++------- Engine/MemcachedEngine.php | 6 ++--- Exception/CacheWriteException.php | 27 ++++++++++++++++++++ Exception/InvalidArgumentException.php | 34 ++++++++++++++++++++++++++ InvalidArgumentException.php | 28 +++++---------------- 6 files changed, 95 insertions(+), 50 deletions(-) create mode 100644 Exception/CacheWriteException.php create mode 100644 Exception/InvalidArgumentException.php diff --git a/Cache.php b/Cache.php index 0c8d8d37f..32ae10473 100644 --- a/Cache.php +++ b/Cache.php @@ -17,6 +17,8 @@ namespace Cake\Cache; use Cake\Cache\Engine\NullEngine; +use Cake\Cache\Exception\CacheWriteException; +use Cake\Cache\Exception\InvalidArgumentException; use Cake\Core\StaticConfigTrait; use RuntimeException; @@ -136,7 +138,7 @@ public static function setRegistry(CacheRegistry $registry): void * Finds and builds the instance of the required engine class. * * @param string $name Name of the config array that needs an engine instance built - * @throws \Cake\Cache\InvalidArgumentException When a cache engine cannot be created. + * @throws \Cake\Cache\Exception\InvalidArgumentException When a cache engine cannot be created. * @throws \RuntimeException If loading of the engine failed. * @return void */ @@ -265,15 +267,12 @@ public static function write(string $key, $value, string $config = 'default'): b $backend = static::pool($config); $success = $backend->set($key, $value); if ($success === false && $value !== '') { - trigger_error( - sprintf( - "%s cache was unable to write '%s' to %s cache", - $config, - $key, - get_class($backend) - ), - E_USER_WARNING - ); + throw new CacheWriteException(sprintf( + "%s cache was unable to write '%s' to %s cache", + $config, + $key, + get_class($backend) + )); } return $success; @@ -299,7 +298,7 @@ public static function write(string $key, $value, string $config = 'default'): b * @param iterable $data An array or Traversable of data to be stored in the cache * @param string $config Optional string configuration name to write to. Defaults to 'default' * @return bool True on success, false on failure - * @throws \Cake\Cache\InvalidArgumentException + * @throws \Cake\Cache\Exception\InvalidArgumentException */ public static function writeMany(iterable $data, string $config = 'default'): bool { @@ -354,7 +353,7 @@ public static function read(string $key, string $config = 'default') * @param string $config optional name of the configuration to use. Defaults to 'default' * @return iterable An array containing, for each of the given $keys, * the cached data or false if cached data could not be retrieved. - * @throws \Cake\Cache\InvalidArgumentException + * @throws \Cake\Cache\Exception\InvalidArgumentException */ public static function readMany(iterable $keys, string $config = 'default'): iterable { @@ -369,7 +368,7 @@ public static function readMany(iterable $keys, string $config = 'default'): ite * @param string $config Optional string configuration name. Defaults to 'default' * @return int|false New value, or false if the data doesn't exist, is not integer, * or if there was an error fetching it. - * @throws \Cake\Cache\InvalidArgumentException When offset < 0 + * @throws \Cake\Cache\Exception\InvalidArgumentException When offset < 0 */ public static function increment(string $key, int $offset = 1, string $config = 'default') { @@ -388,7 +387,7 @@ public static function increment(string $key, int $offset = 1, string $config = * @param string $config Optional string configuration name. Defaults to 'default' * @return int|false New value, or false if the data doesn't exist, is not integer, * or if there was an error fetching it - * @throws \Cake\Cache\InvalidArgumentException when offset < 0 + * @throws \Cake\Cache\Exception\InvalidArgumentException when offset < 0 */ public static function decrement(string $key, int $offset = 1, string $config = 'default') { @@ -445,7 +444,7 @@ public static function delete(string $key, string $config = 'default'): bool * @param iterable $keys Array or Traversable of cache keys to be deleted * @param string $config name of the configuration to use. Defaults to 'default' * @return bool True on success, false on failure. - * @throws \Cake\Cache\InvalidArgumentException + * @throws \Cake\Cache\Exception\InvalidArgumentException */ public static function deleteMany(iterable $keys, string $config = 'default'): bool { @@ -505,7 +504,7 @@ public static function clearGroup(string $group, string $config = 'default'): bo * * @param string|null $group Group name or null to retrieve all group mappings * @return array Map of group and all configuration that has the same group - * @throws \Cake\Cache\InvalidArgumentException + * @throws \Cake\Cache\Exception\InvalidArgumentException */ public static function groupConfigs(?string $group = null): array { diff --git a/CacheEngine.php b/CacheEngine.php index da5bcc719..683d0996c 100644 --- a/CacheEngine.php +++ b/CacheEngine.php @@ -16,6 +16,7 @@ */ namespace Cake\Cache; +use Cake\Cache\Exception\InvalidArgumentException; use Cake\Core\InstanceConfigTrait; use DateInterval; use DateTime; @@ -96,7 +97,7 @@ public function init(array $config = []): bool * * @param string $key Key to check. * @return void - * @throws \Cake\Cache\InvalidArgumentException When the key is not valid. + * @throws \Cake\Cache\Exception\InvalidArgumentException When the key is not valid. */ protected function ensureValidKey($key): void { @@ -111,7 +112,7 @@ protected function ensureValidKey($key): void * @param iterable $iterable The iterable to check. * @param string $check Whether to check keys or values. * @return void - * @throws \Cake\Cache\InvalidArgumentException + * @throws \Cake\Cache\Exception\InvalidArgumentException */ protected function ensureValidType($iterable, string $check = self::CHECK_VALUE): void { @@ -137,7 +138,7 @@ protected function ensureValidType($iterable, string $check = self::CHECK_VALUE) * @param iterable $keys A list of keys that can obtained in a single operation. * @param mixed $default Default value to return for keys that do not exist. * @return iterable A list of key value pairs. Cache keys that do not exist or are stale will have $default as value. - * @throws \Cake\Cache\InvalidArgumentException If $keys is neither an array nor a Traversable, + * @throws \Cake\Cache\Exception\InvalidArgumentException If $keys is neither an array nor a Traversable, * or if any of the $keys are not a legal value. */ public function getMultiple($keys, $default = null): iterable @@ -160,7 +161,7 @@ public function getMultiple($keys, $default = null): iterable * the driver supports TTL then the library may set a default value * for it or let the driver take care of that. * @return bool True on success and false on failure. - * @throws \Cake\Cache\InvalidArgumentException If $values is neither an array nor a Traversable, + * @throws \Cake\Cache\Exception\InvalidArgumentException If $values is neither an array nor a Traversable, * or if any of the $values are not a legal value. */ public function setMultiple($values, $ttl = null): bool @@ -196,7 +197,7 @@ public function setMultiple($values, $ttl = null): bool * * @param iterable $keys A list of string-based keys to be deleted. * @return bool True if the items were successfully removed. False if there was an error. - * @throws \Cake\Cache\InvalidArgumentException If $keys is neither an array nor a Traversable, + * @throws \Cake\Cache\Exception\InvalidArgumentException If $keys is neither an array nor a Traversable, * or if any of the $keys are not a legal value. */ public function deleteMultiple($keys): bool @@ -223,7 +224,7 @@ public function deleteMultiple($keys): bool * * @param string $key The cache item key. * @return bool - * @throws \Cake\Cache\InvalidArgumentException If the $key string is not a legal value. + * @throws \Cake\Cache\Exception\InvalidArgumentException If the $key string is not a legal value. */ public function has($key): bool { @@ -236,7 +237,7 @@ public function has($key): bool * @param string $key The unique key of this item in the cache. * @param mixed $default Default value to return if the key does not exist. * @return mixed The value of the item from the cache, or $default in case of cache miss. - * @throws \Cake\Cache\InvalidArgumentException If the $key string is not a legal value. + * @throws \Cake\Cache\Exception\InvalidArgumentException If the $key string is not a legal value. */ abstract public function get($key, $default = null); @@ -249,7 +250,7 @@ abstract public function get($key, $default = null); * the driver supports TTL then the library may set a default value * for it or let the driver take care of that. * @return bool True on success and false on failure. - * @throws \Cake\Cache\InvalidArgumentException + * @throws \Cake\Cache\Exception\InvalidArgumentException * MUST be thrown if the $key string is not a legal value. */ abstract public function set($key, $value, $ttl = null): bool; @@ -337,7 +338,7 @@ public function groups(): array * * @param string $key the key passed over * @return string Prefixed key with potentially unsafe characters replaced. - * @throws \Cake\Cache\InvalidArgumentException If key's value is invalid. + * @throws \Cake\Cache\Exception\InvalidArgumentException If key's value is invalid. */ protected function _key($key): string { diff --git a/Engine/MemcachedEngine.php b/Engine/MemcachedEngine.php index b714f5056..f490b363e 100644 --- a/Engine/MemcachedEngine.php +++ b/Engine/MemcachedEngine.php @@ -17,7 +17,7 @@ namespace Cake\Cache\Engine; use Cake\Cache\CacheEngine; -use InvalidArgumentException; +use Cake\Cache\Exception\InvalidArgumentException; use Memcached; use RuntimeException; @@ -98,7 +98,7 @@ class MemcachedEngine extends CacheEngine * * @param array $config array of setting for the engine * @return bool True if the engine has been successfully initialized, false if not - * @throws \InvalidArgumentException When you try use authentication without + * @throws \Cake\Cache\Exception\InvalidArgumentException When you try use authentication without * Memcached compiled with SASL support */ public function init(array $config = []): bool @@ -199,7 +199,7 @@ public function init(array $config = []): bool * Settings the memcached instance * * @return void - * @throws \InvalidArgumentException When the Memcached extension is not built + * @throws \Cake\Cache\Exception\InvalidArgumentException When the Memcached extension is not built * with the desired serializer engine. */ protected function _setOptions(): void diff --git a/Exception/CacheWriteException.php b/Exception/CacheWriteException.php new file mode 100644 index 000000000..241ef6539 --- /dev/null +++ b/Exception/CacheWriteException.php @@ -0,0 +1,27 @@ + Date: Wed, 8 Mar 2023 10:56:37 +0530 Subject: [PATCH 074/127] Update "provide" config of various packages. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 96aec1982..7f20c1e9a 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ "psr/simple-cache": "^1.0 || ^2.0" }, "provide": { - "psr/simple-cache-implementation": "^1.0.0" + "psr/simple-cache-implementation": "^1.0 || ^2.0" }, "autoload": { "psr-4": { From 0b9b11294e2f1e1f4f9ccad44bd1cd843e236fe8 Mon Sep 17 00:00:00 2001 From: Mark Story Date: Fri, 10 Mar 2023 23:37:14 -0500 Subject: [PATCH 075/127] Fix build errors --- Engine/MemcachedEngine.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Engine/MemcachedEngine.php b/Engine/MemcachedEngine.php index 31124bc8b..f495df4dc 100644 --- a/Engine/MemcachedEngine.php +++ b/Engine/MemcachedEngine.php @@ -17,9 +17,9 @@ namespace Cake\Cache\Engine; use Cake\Cache\CacheEngine; +use Cake\Cache\InvalidArgumentException; use Cake\Core\Exception\CakeException; use DateInterval; -use InvalidArgumentException; use Memcached; /** From 388dea4f74ed79d31eae8709d47fcae1157c4409 Mon Sep 17 00:00:00 2001 From: Mark Story Date: Fri, 10 Mar 2023 23:42:38 -0500 Subject: [PATCH 076/127] Fix mistake --- Engine/MemcachedEngine.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Engine/MemcachedEngine.php b/Engine/MemcachedEngine.php index f495df4dc..eb33d8c2f 100644 --- a/Engine/MemcachedEngine.php +++ b/Engine/MemcachedEngine.php @@ -17,7 +17,7 @@ namespace Cake\Cache\Engine; use Cake\Cache\CacheEngine; -use Cake\Cache\InvalidArgumentException; +use Cake\Cache\Exception\InvalidArgumentException; use Cake\Core\Exception\CakeException; use DateInterval; use Memcached; From 0c63de0c3cfe828e5953446f6c496c647cfa537f Mon Sep 17 00:00:00 2001 From: ADmad Date: Fri, 10 Mar 2023 12:15:58 +0530 Subject: [PATCH 077/127] Namespace all functions. Add global versions if not already defined. --- Cache.php | 1 + CacheEngine.php | 1 + InvalidArgumentException.php | 2 ++ 3 files changed, 4 insertions(+) diff --git a/Cache.php b/Cache.php index 32ae10473..b91032291 100644 --- a/Cache.php +++ b/Cache.php @@ -21,6 +21,7 @@ use Cake\Cache\Exception\InvalidArgumentException; use Cake\Core\StaticConfigTrait; use RuntimeException; +use function Cake\Core\deprecationWarning; /** * Cache provides a consistent interface to Caching in your application. It allows you diff --git a/CacheEngine.php b/CacheEngine.php index 683d0996c..b37fc672f 100644 --- a/CacheEngine.php +++ b/CacheEngine.php @@ -21,6 +21,7 @@ use DateInterval; use DateTime; use Psr\SimpleCache\CacheInterface; +use function Cake\Core\triggerWarning; /** * Storage engine for CakePHP caching diff --git a/InvalidArgumentException.php b/InvalidArgumentException.php index 8d90447d2..8d0e9e6a5 100644 --- a/InvalidArgumentException.php +++ b/InvalidArgumentException.php @@ -1,6 +1,8 @@ Date: Tue, 4 Apr 2023 12:40:19 +0200 Subject: [PATCH 078/127] Use 0770 as default perms. --- Engine/FileEngine.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Engine/FileEngine.php b/Engine/FileEngine.php index 35252b98e..a7137dcba 100644 --- a/Engine/FileEngine.php +++ b/Engine/FileEngine.php @@ -371,7 +371,7 @@ protected function _setKey(string $key, bool $createKey = false): bool $dir = $this->_config['path'] . $groups; if (!is_dir($dir)) { - mkdir($dir, 0775, true); + mkdir($dir, 0770, true); } $path = new SplFileInfo($dir . $key); @@ -418,7 +418,7 @@ protected function _active(): bool $success = true; if (!is_dir($path)) { // phpcs:disable - $success = @mkdir($path, 0775, true); + $success = @mkdir($path, 0770, true); // phpcs:enable } From 01ca89cf0935bac534adf5592fe8708746944b05 Mon Sep 17 00:00:00 2001 From: mscherer Date: Tue, 4 Apr 2023 13:05:01 +0200 Subject: [PATCH 079/127] Use dirMask option to configure the folder perms. --- Engine/FileEngine.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Engine/FileEngine.php b/Engine/FileEngine.php index a7137dcba..9e786787a 100644 --- a/Engine/FileEngine.php +++ b/Engine/FileEngine.php @@ -50,6 +50,7 @@ class FileEngine extends CacheEngine * handy for deleting a complete group from cache. * - `lock` Used by FileCache. Should files be locked before writing to them? * - `mask` The mask used for created files + * - `dirMask` The mask used for created folders * - `path` Path to where cachefiles should be saved. Defaults to system's temp dir. * - `prefix` Prepended to all entries. Good for when you need to share a keyspace * with either another cache config or another application. @@ -63,6 +64,7 @@ class FileEngine extends CacheEngine 'groups' => [], 'lock' => true, 'mask' => 0664, + 'dirMask' => 0770, 'path' => null, 'prefix' => 'cake_', 'serialize' => true, @@ -371,7 +373,7 @@ protected function _setKey(string $key, bool $createKey = false): bool $dir = $this->_config['path'] . $groups; if (!is_dir($dir)) { - mkdir($dir, 0770, true); + mkdir($dir, $this->_config['dirMask'], true); } $path = new SplFileInfo($dir . $key); @@ -418,7 +420,7 @@ protected function _active(): bool $success = true; if (!is_dir($path)) { // phpcs:disable - $success = @mkdir($path, 0770, true); + $success = @mkdir($path, $this->_config['dirMask'], true); // phpcs:enable } From c7502588fdfca2d8abf55c7958d40e3356902089 Mon Sep 17 00:00:00 2001 From: Kevin Pfeifer Date: Tue, 9 May 2023 21:15:36 +0200 Subject: [PATCH 080/127] remove deprecations --- Exception/InvalidArgumentException.php | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Exception/InvalidArgumentException.php b/Exception/InvalidArgumentException.php index 1931e65ac..660f5aab5 100644 --- a/Exception/InvalidArgumentException.php +++ b/Exception/InvalidArgumentException.php @@ -25,10 +25,3 @@ class InvalidArgumentException extends CakeException implements InvalidArgumentInterface { } -// phpcs:disable -// @deprecated Backwards compatibility alias. Will be removed in 5.0 -class_alias( - 'Cake\Cache\Exception\InvalidArgumentException', - 'Cake\Cache\InvalidArgumentException' -); -// phpcs:enable From afbda69efb583578113456720276444542b53770 Mon Sep 17 00:00:00 2001 From: ADmad Date: Sun, 1 Oct 2023 02:14:44 +0530 Subject: [PATCH 081/127] Update docs URLs --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2f319dfe2..2b282921d 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,6 @@ the callback will be executed and the returned data will be cached for future ca ## Documentation -Please make sure you check the [official documentation](https://book.cakephp.org/4/en/core-libraries/caching.html) +Please make sure you check the [official documentation](https://book.cakephp.org/5/en/core-libraries/caching.html) From 8523d8314a15fae5e9299d382b8e32c2e2620c63 Mon Sep 17 00:00:00 2001 From: mscherer Date: Fri, 24 Nov 2023 14:50:34 +0100 Subject: [PATCH 082/127] Local Redis seems to be able to return false --- Engine/RedisEngine.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Engine/RedisEngine.php b/Engine/RedisEngine.php index 9e9768253..23d5309d2 100644 --- a/Engine/RedisEngine.php +++ b/Engine/RedisEngine.php @@ -227,7 +227,7 @@ public function delete(string $key): bool { $key = $this->_key($key); - return $this->_Redis->del($key) > 0; + return (int)$this->_Redis->del($key) > 0; } /** @@ -242,7 +242,7 @@ public function deleteAsync(string $key): bool { $key = $this->_key($key); - return $this->_Redis->unlink($key) > 0; + return (int)$this->_Redis->unlink($key) > 0; } /** @@ -266,7 +266,7 @@ public function clear(): bool } foreach ($keys as $key) { - $isDeleted = ($this->_Redis->del($key) > 0); + $isDeleted = ((int)$this->_Redis->del($key) > 0); $isAllDeleted = $isAllDeleted && $isDeleted; } } @@ -297,7 +297,7 @@ public function clearBlocking(): bool } foreach ($keys as $key) { - $isDeleted = ($this->_Redis->unlink($key) > 0); + $isDeleted = ((int)$this->_Redis->unlink($key) > 0); $isAllDeleted = $isAllDeleted && $isDeleted; } } From 9c1b4fd28eab716fd759abd5235446907a864c0f Mon Sep 17 00:00:00 2001 From: mscherer Date: Sat, 9 Dec 2023 07:19:14 +0100 Subject: [PATCH 083/127] Less cloaking and more strict comparison where possible. --- Engine/ApcuEngine.php | 2 +- Engine/MemcachedEngine.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Engine/ApcuEngine.php b/Engine/ApcuEngine.php index beb68f5bb..8cb611e94 100644 --- a/Engine/ApcuEngine.php +++ b/Engine/ApcuEngine.php @@ -190,7 +190,7 @@ public function add(string $key, mixed $value): bool */ public function groups(): array { - if (empty($this->_compiledGroupNames)) { + if (!$this->_compiledGroupNames) { foreach ($this->_config['groups'] as $group) { $this->_compiledGroupNames[] = $this->_config['prefix'] . $group; } diff --git a/Engine/MemcachedEngine.php b/Engine/MemcachedEngine.php index eb33d8c2f..0fbeb427e 100644 --- a/Engine/MemcachedEngine.php +++ b/Engine/MemcachedEngine.php @@ -471,7 +471,7 @@ public function add(string $key, mixed $value): bool */ public function groups(): array { - if (empty($this->_compiledGroupNames)) { + if (!$this->_compiledGroupNames) { foreach ($this->_config['groups'] as $group) { $this->_compiledGroupNames[] = $this->_config['prefix'] . $group; } From 3af53307fcac61103a5d2194dffa6d522ef39588 Mon Sep 17 00:00:00 2001 From: "Frank de Graaf (Phally)" Date: Fri, 19 May 2023 21:18:04 +0200 Subject: [PATCH 084/127] Adds TLS support to RedisEngine. TLS support was added in php-redis v5.3.0. This adds support for `'tls' => true` in the engine configuration and using `tls=true` in the DSN configuration. Additionally, support was added for SSL context options. In the DSN one can now use `ssl_ca`, `ssl_key`, and `ssl_cert` as well, similar to the MySQL database driver. Closes #17130 --- Engine/RedisEngine.php | 104 +++++++++++++++++++++++++++++++++++------ 1 file changed, 91 insertions(+), 13 deletions(-) diff --git a/Engine/RedisEngine.php b/Engine/RedisEngine.php index dc90ef72f..cdd479fb2 100644 --- a/Engine/RedisEngine.php +++ b/Engine/RedisEngine.php @@ -45,6 +45,7 @@ class RedisEngine extends CacheEngine * - `password` Redis server password. * - `persistent` Connect to the Redis server with a persistent connection * - `port` port number to the Redis server. + * - `tls` connect to the Redis server using TLS. * - `prefix` Prefix appended to all entries. Good for when you need to share a keyspace * with either another cache config or another application. * - `scanCount` Number of keys to ask for each scan (default: 10) @@ -61,6 +62,7 @@ class RedisEngine extends CacheEngine 'password' => false, 'persistent' => true, 'port' => 6379, + 'tls' => false, 'prefix' => 'cake_', 'host' => null, 'server' => '127.0.0.1', @@ -99,24 +101,29 @@ public function init(array $config = []): bool */ protected function _connect(): bool { + $tls = $this->_config['tls'] === true ? 'tls://' : ''; + + $map = [ + 'ssl_ca' => 'cafile', + 'ssl_key' => 'local_pk', + 'ssl_cert' => 'local_cert', + ]; + + $ssl = []; + foreach ($map as $key => $context) { + if (!empty($this->_config[$key])) { + $ssl[$context] = $this->_config[$key]; + } + } + try { - $this->_Redis = new Redis(); + $this->_Redis = $this->_createRedisInstance(); if (!empty($this->_config['unix_socket'])) { $return = $this->_Redis->connect($this->_config['unix_socket']); } elseif (empty($this->_config['persistent'])) { - $return = $this->_Redis->connect( - $this->_config['server'], - (int)$this->_config['port'], - (int)$this->_config['timeout'] - ); + $return = $this->_connectTransient($tls . $this->_config['server'], $ssl); } else { - $persistentId = $this->_config['port'] . $this->_config['timeout'] . $this->_config['database']; - $return = $this->_Redis->pconnect( - $this->_config['server'], - (int)$this->_config['port'], - (int)$this->_config['timeout'], - $persistentId - ); + $return = $this->_connectPersistent($tls . $this->_config['server'], $ssl); } } catch (RedisException $e) { if (class_exists(Log::class)) { @@ -135,6 +142,67 @@ protected function _connect(): bool return $return; } + /** + * Connects to a Redis server using a new connection. + * + * @param string $server Server to connect to. + * @param array $ssl SSL context options. + * @throws \RedisException + * @return bool True if Redis server was connected + */ + protected function _connectTransient($server, array $ssl): bool + { + if (empty($ssl)) { + return $this->_Redis->connect( + $server, + (int)$this->_config['port'], + (int)$this->_config['timeout'] + ); + } + + return $this->_Redis->connect( + $server, + (int)$this->_config['port'], + (int)$this->_config['timeout'], + null, + 0, + 0.0, + ['ssl' => $ssl] + ); + } + + /** + * Connects to a Redis server using a persistent connection. + * + * @param string $server Server to connect to. + * @param array $ssl SSL context options. + * @throws \RedisException + * @return bool True if Redis server was connected + */ + protected function _connectPersistent($server, array $ssl): bool + { + $persistentId = $this->_config['port'] . $this->_config['timeout'] . $this->_config['database']; + + if (empty($ssl)) { + return $this->_Redis->pconnect( + $server, + (int)$this->_config['port'], + (int)$this->_config['timeout'], + $persistentId + ); + } + + return $this->_Redis->pconnect( + $server, + (int)$this->_config['port'], + (int)$this->_config['timeout'], + $persistentId, + 0, + 0.0, + ['ssl' => $ssl] + ); + } + /** * Write data for key into cache. * @@ -394,6 +462,16 @@ protected function unserialize(string $value) return unserialize($value); } + /** + * Create new Redis instance. + * + * @return \Redis + */ + protected function _createRedisInstance(): Redis + { + return new Redis(); + } + /** * Disconnects from the redis server */ From 054c44d06f4ad3fa3aee56143429572c35f18ef1 Mon Sep 17 00:00:00 2001 From: mscherer Date: Mon, 8 Jan 2024 18:38:53 +0100 Subject: [PATCH 085/127] Prefer defined vars over undefined checks. --- CacheEngine.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CacheEngine.php b/CacheEngine.php index 79480df33..ac483ff47 100644 --- a/CacheEngine.php +++ b/CacheEngine.php @@ -162,6 +162,7 @@ public function setMultiple(iterable $values, DateInterval|int|null $ttl = null) { $this->ensureValidType($values, self::CHECK_KEY); + $restore = null; if ($ttl !== null) { $restore = $this->getConfig('duration'); $this->setConfig('duration', $ttl); @@ -176,7 +177,7 @@ public function setMultiple(iterable $values, DateInterval|int|null $ttl = null) return true; } finally { - if (isset($restore)) { + if ($restore !== null) { $this->setConfig('duration', $restore); } } From 7f24666574fddd5c69b52463e07bc09e97b4277d Mon Sep 17 00:00:00 2001 From: Mark Story Date: Sun, 14 Jan 2024 22:21:58 -0500 Subject: [PATCH 086/127] Fix phpcs errors. --- Engine/RedisEngine.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Engine/RedisEngine.php b/Engine/RedisEngine.php index 385b8189b..8af478714 100644 --- a/Engine/RedisEngine.php +++ b/Engine/RedisEngine.php @@ -151,7 +151,7 @@ protected function _connect(): bool * @throws \RedisException * @return bool True if Redis server was connected */ - protected function _connectTransient($server, array $ssl): bool + protected function _connectTransient(string $server, array $ssl): bool { if (empty($ssl)) { return $this->_Redis->connect( @@ -180,7 +180,7 @@ protected function _connectTransient($server, array $ssl): bool * @throws \RedisException * @return bool True if Redis server was connected */ - protected function _connectPersistent($server, array $ssl): bool + protected function _connectPersistent(string $server, array $ssl): bool { $persistentId = $this->_config['port'] . $this->_config['timeout'] . $this->_config['database']; From 484d247c7db9ff91a63fe8fdc53cadac23013d0d Mon Sep 17 00:00:00 2001 From: Mark Scherer Date: Tue, 27 Feb 2024 17:49:04 +0100 Subject: [PATCH 087/127] Fix up array list<> docblocks. (#17597) * Fix up array list<> docblocks. --------- Co-authored-by: ADmad --- CacheEngine.php | 2 +- Engine/ApcuEngine.php | 4 ++-- Engine/ArrayEngine.php | 2 +- Engine/MemcachedEngine.php | 4 ++-- Engine/RedisEngine.php | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CacheEngine.php b/CacheEngine.php index ac483ff47..6bd5c37ad 100644 --- a/CacheEngine.php +++ b/CacheEngine.php @@ -318,7 +318,7 @@ abstract public function clearGroup(string $group): bool; * and returns the `group value` for each of them, this is * the token representing each group in the cache key * - * @return array + * @return list */ public function groups(): array { diff --git a/Engine/ApcuEngine.php b/Engine/ApcuEngine.php index 8cb611e94..2daf50d3d 100644 --- a/Engine/ApcuEngine.php +++ b/Engine/ApcuEngine.php @@ -30,7 +30,7 @@ class ApcuEngine extends CacheEngine * Contains the compiled group names * (prefixed with the global configuration prefix) * - * @var array + * @var list */ protected array $_compiledGroupNames = []; @@ -184,7 +184,7 @@ public function add(string $key, mixed $value): bool * If the group initial value was not found, then it initializes * the group accordingly. * - * @return array + * @return list * @link https://secure.php.net/manual/en/function.apcu-fetch.php * @link https://secure.php.net/manual/en/function.apcu-store.php */ diff --git a/Engine/ArrayEngine.php b/Engine/ArrayEngine.php index 6b1f2500c..7eeecbf85 100644 --- a/Engine/ArrayEngine.php +++ b/Engine/ArrayEngine.php @@ -153,7 +153,7 @@ public function clear(): bool * If the group initial value was not found, then it initializes * the group accordingly. * - * @return array + * @return list */ public function groups(): array { diff --git a/Engine/MemcachedEngine.php b/Engine/MemcachedEngine.php index 0fbeb427e..e62cf5752 100644 --- a/Engine/MemcachedEngine.php +++ b/Engine/MemcachedEngine.php @@ -88,7 +88,7 @@ class MemcachedEngine extends CacheEngine protected array $_serializers = []; /** - * @var array + * @var list */ protected array $_compiledGroupNames = []; @@ -467,7 +467,7 @@ public function add(string $key, mixed $value): bool * If the group initial value was not found, then it initializes * the group accordingly. * - * @return array + * @return list */ public function groups(): array { diff --git a/Engine/RedisEngine.php b/Engine/RedisEngine.php index 8af478714..101834733 100644 --- a/Engine/RedisEngine.php +++ b/Engine/RedisEngine.php @@ -400,7 +400,7 @@ public function add(string $key, mixed $value): bool * If the group initial value was not found, then it initializes * the group accordingly. * - * @return array + * @return list */ public function groups(): array { From 76fbb7a85f96f5d18fae8a1d34211c0116a6e09a Mon Sep 17 00:00:00 2001 From: ADmad Date: Sat, 22 Jun 2024 00:14:46 +0530 Subject: [PATCH 088/127] Replace md5 usage with xxh128. The latter is much faster than md5. xxh128 is not cryptographically secure but that's not required in the context it is used. --- CacheEngine.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CacheEngine.php b/CacheEngine.php index 6bd5c37ad..be7656af2 100644 --- a/CacheEngine.php +++ b/CacheEngine.php @@ -341,7 +341,7 @@ protected function _key(string $key): string $prefix = ''; if ($this->_groupPrefix) { - $prefix = md5(implode('_', $this->groups())); + $prefix = hash('xxh128', implode('_', $this->groups())); } $key = preg_replace('/[\s]+/', '_', $key); From 578bce04f1a83b029ce0d42e7f759df00a42fd44 Mon Sep 17 00:00:00 2001 From: Adam Halfar Date: Thu, 1 Aug 2024 22:31:53 +0200 Subject: [PATCH 089/127] Rector fixes from rule set LevelSetList::UP_TO_PHP_81 --- Cache.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cache.php b/Cache.php index adcc37f82..8b5212224 100644 --- a/Cache.php +++ b/Cache.php @@ -253,7 +253,7 @@ public static function write(string $key, mixed $value, string $config = 'defaul "%s cache was unable to write '%s' to %s cache", $config, $key, - get_class($backend) + $backend::class )); } From 1f24f79740d7a220cbfa502e53f6ca95dd69512f Mon Sep 17 00:00:00 2001 From: Adam Halfar Date: Sun, 4 Aug 2024 13:33:16 +0200 Subject: [PATCH 090/127] Add changes from rector rule StrlenZeroToIdenticalEmptyStringRector --- CacheEngine.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CacheEngine.php b/CacheEngine.php index be7656af2..3af120acd 100644 --- a/CacheEngine.php +++ b/CacheEngine.php @@ -102,7 +102,7 @@ public function init(array $config = []): bool */ protected function ensureValidKey(mixed $key): void { - if (!is_string($key) || strlen($key) === 0) { + if (!is_string($key) || $key === '') { throw new InvalidArgumentException('A cache key must be a non-empty string.'); } } From bb716c94071149498215d1e38d7e5f1c646ac5b9 Mon Sep 17 00:00:00 2001 From: Adam Halfar Date: Sun, 4 Aug 2024 16:49:47 +0200 Subject: [PATCH 091/127] Add changes from rector rule ConsistentImplodeRector --- Engine/FileEngine.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Engine/FileEngine.php b/Engine/FileEngine.php index 0c9630fc6..936b19bf9 100644 --- a/Engine/FileEngine.php +++ b/Engine/FileEngine.php @@ -128,7 +128,7 @@ public function set(string $key, mixed $value, DateInterval|int|null $ttl = null } $expires = time() + $this->duration($ttl); - $contents = implode([$expires, PHP_EOL, $value, PHP_EOL]); + $contents = implode('', [$expires, PHP_EOL, $value, PHP_EOL]); if ($this->_config['lock']) { $this->_File->flock(LOCK_EX); From 4dd302ef81f3c0379600766f862a699ba6f87e0d Mon Sep 17 00:00:00 2001 From: Adam Haflar <47174548+Harfusha@users.noreply.github.com> Date: Tue, 6 Aug 2024 19:12:04 +0200 Subject: [PATCH 092/127] Add changes from rector rule ReturnEarlyIfVariableRector (#17800) * Add changes from rector rule ReturnEarlyIfVariableRector --- Engine/FileEngine.php | 2 +- Engine/RedisEngine.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Engine/FileEngine.php b/Engine/FileEngine.php index 936b19bf9..875b63cb6 100644 --- a/Engine/FileEngine.php +++ b/Engine/FileEngine.php @@ -194,7 +194,7 @@ public function get(string $key, mixed $default = null): mixed $data = trim($data); if ($data !== '' && !empty($this->_config['serialize'])) { - $data = unserialize($data); + return unserialize($data); } return $data; diff --git a/Engine/RedisEngine.php b/Engine/RedisEngine.php index 101834733..ba4c7ee5a 100644 --- a/Engine/RedisEngine.php +++ b/Engine/RedisEngine.php @@ -137,7 +137,7 @@ protected function _connect(): bool $return = $this->_Redis->auth($this->_config['password']); } if ($return) { - $return = $this->_Redis->select((int)$this->_config['database']); + return $this->_Redis->select((int)$this->_config['database']); } return $return; From 1ed65abec265b0baaf962975a23fe8e4eb7cfbea Mon Sep 17 00:00:00 2001 From: Adam Halfar Date: Thu, 22 Aug 2024 21:24:04 +0200 Subject: [PATCH 093/127] Rector changes after merge --- Engine/RedisEngine.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Engine/RedisEngine.php b/Engine/RedisEngine.php index ba4c7ee5a..2ba15fd8c 100644 --- a/Engine/RedisEngine.php +++ b/Engine/RedisEngine.php @@ -153,7 +153,7 @@ protected function _connect(): bool */ protected function _connectTransient(string $server, array $ssl): bool { - if (empty($ssl)) { + if ($ssl === []) { return $this->_Redis->connect( $server, (int)$this->_config['port'], @@ -184,7 +184,7 @@ protected function _connectPersistent(string $server, array $ssl): bool { $persistentId = $this->_config['port'] . $this->_config['timeout'] . $this->_config['database']; - if (empty($ssl)) { + if ($ssl === []) { return $this->_Redis->pconnect( $server, (int)$this->_config['port'], From 7180afae57dc1965abcb0d4b7a60b7c32ec6d49d Mon Sep 17 00:00:00 2001 From: ADmad Date: Sat, 20 Jul 2024 19:37:40 +0530 Subject: [PATCH 094/127] Bump up Cake dependencies versions in split packages. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index a1783006c..8bab39996 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ }, "require": { "php": ">=8.1", - "cakephp/core": "^5.0", + "cakephp/core": "^5.1", "psr/simple-cache": "^2.0 || ^3.0" }, "provide": { From a9c9a1238c230dc11f045fc7d1ee7e2c3774ef42 Mon Sep 17 00:00:00 2001 From: Kevin Pfeifer Date: Sun, 17 Nov 2024 18:37:29 +0100 Subject: [PATCH 095/127] phpstan 2.0 (#18014) * get ready for phpstan 2.0 * undo array_values fix * add review changes * fix stan * phpstan 2.0 * fix phpstan for split packages * fix phpstan for tests * re-add method_exists * Apply suggestions from code review Co-authored-by: ADmad --------- Co-authored-by: ADmad --- Engine/FileEngine.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Engine/FileEngine.php b/Engine/FileEngine.php index 875b63cb6..8ae5f4ab9 100644 --- a/Engine/FileEngine.php +++ b/Engine/FileEngine.php @@ -245,12 +245,12 @@ public function clear(): bool $this->_config['path'], FilesystemIterator::SKIP_DOTS ); - /** @var \RecursiveDirectoryIterator<\SplFileInfo> $iterator Coerce for phpstan/psalm */ $iterator = new RecursiveIteratorIterator( $directory, RecursiveIteratorIterator::SELF_FIRST ); $cleared = []; + /** @var \SplFileInfo $fileInfo */ foreach ($iterator as $fileInfo) { if ($fileInfo->isFile()) { unset($fileInfo); @@ -457,7 +457,6 @@ public function clearGroup(string $group): bool $directoryIterator, RecursiveIteratorIterator::CHILD_FIRST ); - /** @var array<\SplFileInfo> $filtered */ $filtered = new CallbackFilterIterator( $contents, function (SplFileInfo $current) use ($group, $prefix) { @@ -476,6 +475,7 @@ function (SplFileInfo $current) use ($group, $prefix) { ); } ); + /** @var \SplFileInfo $object */ foreach ($filtered as $object) { $path = $object->getPathname(); unset($object); From 8f77162bdf5b6ee29a9df4a869462869bd1f58c9 Mon Sep 17 00:00:00 2001 From: mscherer Date: Wed, 20 Nov 2024 00:54:30 +0100 Subject: [PATCH 096/127] Fix up list array. --- CacheEngine.php | 2 +- Engine/ApcuEngine.php | 4 ++-- Engine/ArrayEngine.php | 2 +- Engine/MemcachedEngine.php | 4 ++-- Engine/RedisEngine.php | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CacheEngine.php b/CacheEngine.php index 3af120acd..22a180fc0 100644 --- a/CacheEngine.php +++ b/CacheEngine.php @@ -318,7 +318,7 @@ abstract public function clearGroup(string $group): bool; * and returns the `group value` for each of them, this is * the token representing each group in the cache key * - * @return list + * @return array */ public function groups(): array { diff --git a/Engine/ApcuEngine.php b/Engine/ApcuEngine.php index 2daf50d3d..8cb611e94 100644 --- a/Engine/ApcuEngine.php +++ b/Engine/ApcuEngine.php @@ -30,7 +30,7 @@ class ApcuEngine extends CacheEngine * Contains the compiled group names * (prefixed with the global configuration prefix) * - * @var list + * @var array */ protected array $_compiledGroupNames = []; @@ -184,7 +184,7 @@ public function add(string $key, mixed $value): bool * If the group initial value was not found, then it initializes * the group accordingly. * - * @return list + * @return array * @link https://secure.php.net/manual/en/function.apcu-fetch.php * @link https://secure.php.net/manual/en/function.apcu-store.php */ diff --git a/Engine/ArrayEngine.php b/Engine/ArrayEngine.php index 7eeecbf85..6b1f2500c 100644 --- a/Engine/ArrayEngine.php +++ b/Engine/ArrayEngine.php @@ -153,7 +153,7 @@ public function clear(): bool * If the group initial value was not found, then it initializes * the group accordingly. * - * @return list + * @return array */ public function groups(): array { diff --git a/Engine/MemcachedEngine.php b/Engine/MemcachedEngine.php index e62cf5752..0fbeb427e 100644 --- a/Engine/MemcachedEngine.php +++ b/Engine/MemcachedEngine.php @@ -88,7 +88,7 @@ class MemcachedEngine extends CacheEngine protected array $_serializers = []; /** - * @var list + * @var array */ protected array $_compiledGroupNames = []; @@ -467,7 +467,7 @@ public function add(string $key, mixed $value): bool * If the group initial value was not found, then it initializes * the group accordingly. * - * @return list + * @return array */ public function groups(): array { diff --git a/Engine/RedisEngine.php b/Engine/RedisEngine.php index 2ba15fd8c..68d92b3a6 100644 --- a/Engine/RedisEngine.php +++ b/Engine/RedisEngine.php @@ -400,7 +400,7 @@ public function add(string $key, mixed $value): bool * If the group initial value was not found, then it initializes * the group accordingly. * - * @return list + * @return array */ public function groups(): array { From 6655b5bae18dfc48d754e9d126e70fb5d0febe20 Mon Sep 17 00:00:00 2001 From: Mark Scherer Date: Fri, 22 Nov 2024 13:03:02 +0100 Subject: [PATCH 097/127] CS: Trailing comma on function calls (#18032) * CS: Trailing comma on function calls * Fix CS. * Fix CS. * Remove debug call --------- Co-authored-by: Mark Story --- Cache.php | 6 +++--- CacheRegistry.php | 4 ++-- Engine/ApcuEngine.php | 4 ++-- Engine/FileEngine.php | 14 +++++++------- Engine/MemcachedEngine.php | 16 ++++++++-------- Engine/RedisEngine.php | 8 ++++---- 6 files changed, 26 insertions(+), 26 deletions(-) diff --git a/Cache.php b/Cache.php index 8b5212224..c69d9aa24 100644 --- a/Cache.php +++ b/Cache.php @@ -143,7 +143,7 @@ protected static function _buildEngine(string $name): void if (empty(static::$_config[$name]['className'])) { throw new InvalidArgumentException( - sprintf('The `%s` cache configuration does not exist.', $name) + sprintf('The `%s` cache configuration does not exist.', $name), ); } @@ -166,7 +166,7 @@ protected static function _buildEngine(string $name): void if ($config['fallback'] === $name) { throw new InvalidArgumentException(sprintf( '`%s` cache configuration cannot fallback to itself.', - $name + $name, ), 0, $e); } @@ -253,7 +253,7 @@ public static function write(string $key, mixed $value, string $config = 'defaul "%s cache was unable to write '%s' to %s cache", $config, $key, - $backend::class + $backend::class, )); } diff --git a/CacheRegistry.php b/CacheRegistry.php index 564a0040f..5f7f78492 100644 --- a/CacheRegistry.php +++ b/CacheRegistry.php @@ -85,8 +85,8 @@ protected function _create(object|string $class, string $alias, array $config): throw new CakeException( sprintf( 'Cache engine `%s` is not properly configured. Check error log for additional information.', - $instance::class - ) + $instance::class, + ), ); } diff --git a/Engine/ApcuEngine.php b/Engine/ApcuEngine.php index 2daf50d3d..0aa273b56 100644 --- a/Engine/ApcuEngine.php +++ b/Engine/ApcuEngine.php @@ -145,7 +145,7 @@ public function clear(): bool if (class_exists(APCUIterator::class, false)) { $iterator = new APCUIterator( '/^' . preg_quote($this->_config['prefix'], '/') . '/', - APC_ITER_NONE + APC_ITER_NONE, ); apcu_delete($iterator); @@ -204,7 +204,7 @@ public function groups(): array $value = 1; if (apcu_store($group, $value) === false) { $this->warning( - sprintf('Failed to store key `%s` with value `%s` into APCu cache.', $group, $value) + sprintf('Failed to store key `%s` with value `%s` into APCu cache.', $group, $value), ); } $groups[$group] = $value; diff --git a/Engine/FileEngine.php b/Engine/FileEngine.php index 875b63cb6..c57910885 100644 --- a/Engine/FileEngine.php +++ b/Engine/FileEngine.php @@ -243,12 +243,12 @@ public function clear(): bool $directory = new RecursiveDirectoryIterator( $this->_config['path'], - FilesystemIterator::SKIP_DOTS + FilesystemIterator::SKIP_DOTS, ); /** @var \RecursiveDirectoryIterator<\SplFileInfo> $iterator Coerce for phpstan/psalm */ $iterator = new RecursiveIteratorIterator( $directory, - RecursiveIteratorIterator::SELF_FIRST + RecursiveIteratorIterator::SELF_FIRST, ); $cleared = []; foreach ($iterator as $fileInfo) { @@ -394,7 +394,7 @@ protected function _setKey(string $key, bool $createKey = false): bool trigger_error(sprintf( 'Could not apply permission mask `%s` on cache file `%s`', $this->_File->getPathname(), - $this->_config['mask'] + $this->_config['mask'], ), E_USER_WARNING); } } @@ -423,7 +423,7 @@ protected function _active(): bool $this->_init = false; trigger_error(sprintf( '%s is not writable', - $this->_config['path'] + $this->_config['path'], ), E_USER_WARNING); } @@ -455,7 +455,7 @@ public function clearGroup(string $group): bool $directoryIterator = new RecursiveDirectoryIterator($this->_config['path']); $contents = new RecursiveIteratorIterator( $directoryIterator, - RecursiveIteratorIterator::CHILD_FIRST + RecursiveIteratorIterator::CHILD_FIRST, ); /** @var array<\SplFileInfo> $filtered */ $filtered = new CallbackFilterIterator( @@ -472,9 +472,9 @@ function (SplFileInfo $current) use ($group, $prefix) { return str_contains( $current->getPathname(), - DIRECTORY_SEPARATOR . $group . DIRECTORY_SEPARATOR + DIRECTORY_SEPARATOR . $group . DIRECTORY_SEPARATOR, ); - } + }, ); foreach ($filtered as $object) { $path = $object->getPathname(); diff --git a/Engine/MemcachedEngine.php b/Engine/MemcachedEngine.php index e62cf5752..7360dbf9e 100644 --- a/Engine/MemcachedEngine.php +++ b/Engine/MemcachedEngine.php @@ -154,7 +154,7 @@ public function init(array $config = []): bool throw new InvalidArgumentException( 'Invalid cache configuration. Multiple persistent cache configurations are detected' . ' with different `servers` values. `servers` values for persistent cache configurations' . - ' must be the same when using the same persistence id.' + ' must be the same when using the same persistence id.', ); } } @@ -180,20 +180,20 @@ public function init(array $config = []): bool if (empty($this->_config['username']) && !empty($this->_config['login'])) { throw new InvalidArgumentException( - 'Please pass "username" instead of "login" for connecting to Memcached' + 'Please pass "username" instead of "login" for connecting to Memcached', ); } if ($this->_config['username'] !== null && $this->_config['password'] !== null) { if (!method_exists($this->_Memcached, 'setSaslAuthData')) { throw new InvalidArgumentException( - 'Memcached extension is not built with SASL support' + 'Memcached extension is not built with SASL support', ); } $this->_Memcached->setOption(Memcached::OPT_BINARY_PROTOCOL, true); $this->_Memcached->setSaslAuthData( $this->_config['username'], - $this->_config['password'] + $this->_config['password'], ); } @@ -214,7 +214,7 @@ protected function _setOptions(): void $serializer = strtolower($this->_config['serialize']); if (!isset($this->_serializers[$serializer])) { throw new InvalidArgumentException( - sprintf('`%s` is not a valid serializer engine for Memcached.', $serializer) + sprintf('`%s` is not a valid serializer engine for Memcached.', $serializer), ); } @@ -223,13 +223,13 @@ protected function _setOptions(): void !constant('Memcached::HAVE_' . strtoupper($serializer)) ) { throw new InvalidArgumentException( - sprintf('Memcached extension is not compiled with `%s` support.', $serializer) + sprintf('Memcached extension is not compiled with `%s` support.', $serializer), ); } $this->_Memcached->setOption( Memcached::OPT_SERIALIZER, - $this->_serializers[$serializer] + $this->_serializers[$serializer], ); // Check for Amazon ElastiCache instance @@ -242,7 +242,7 @@ protected function _setOptions(): void $this->_Memcached->setOption( Memcached::OPT_COMPRESSION, - (bool)$this->_config['compress'] + (bool)$this->_config['compress'], ); } diff --git a/Engine/RedisEngine.php b/Engine/RedisEngine.php index 2ba15fd8c..d45840982 100644 --- a/Engine/RedisEngine.php +++ b/Engine/RedisEngine.php @@ -157,7 +157,7 @@ protected function _connectTransient(string $server, array $ssl): bool return $this->_Redis->connect( $server, (int)$this->_config['port'], - (int)$this->_config['timeout'] + (int)$this->_config['timeout'], ); } @@ -168,7 +168,7 @@ protected function _connectTransient(string $server, array $ssl): bool null, 0, 0.0, - ['ssl' => $ssl] + ['ssl' => $ssl], ); } @@ -189,7 +189,7 @@ protected function _connectPersistent(string $server, array $ssl): bool $server, (int)$this->_config['port'], (int)$this->_config['timeout'], - $persistentId + $persistentId, ); } @@ -200,7 +200,7 @@ protected function _connectPersistent(string $server, array $ssl): bool $persistentId, 0, 0.0, - ['ssl' => $ssl] + ['ssl' => $ssl], ); } From 2f627d7b24862f0b70775e9d406595599211a4e8 Mon Sep 17 00:00:00 2001 From: mscherer Date: Fri, 22 Nov 2024 17:07:25 +0100 Subject: [PATCH 098/127] Merge 5.x into 5.next --- Cache.php | 6 +++--- CacheRegistry.php | 4 ++-- Engine/ApcuEngine.php | 4 ++-- Engine/FileEngine.php | 14 +++++++------- Engine/MemcachedEngine.php | 16 ++++++++-------- Engine/RedisEngine.php | 8 ++++---- 6 files changed, 26 insertions(+), 26 deletions(-) diff --git a/Cache.php b/Cache.php index 8b5212224..c69d9aa24 100644 --- a/Cache.php +++ b/Cache.php @@ -143,7 +143,7 @@ protected static function _buildEngine(string $name): void if (empty(static::$_config[$name]['className'])) { throw new InvalidArgumentException( - sprintf('The `%s` cache configuration does not exist.', $name) + sprintf('The `%s` cache configuration does not exist.', $name), ); } @@ -166,7 +166,7 @@ protected static function _buildEngine(string $name): void if ($config['fallback'] === $name) { throw new InvalidArgumentException(sprintf( '`%s` cache configuration cannot fallback to itself.', - $name + $name, ), 0, $e); } @@ -253,7 +253,7 @@ public static function write(string $key, mixed $value, string $config = 'defaul "%s cache was unable to write '%s' to %s cache", $config, $key, - $backend::class + $backend::class, )); } diff --git a/CacheRegistry.php b/CacheRegistry.php index 564a0040f..5f7f78492 100644 --- a/CacheRegistry.php +++ b/CacheRegistry.php @@ -85,8 +85,8 @@ protected function _create(object|string $class, string $alias, array $config): throw new CakeException( sprintf( 'Cache engine `%s` is not properly configured. Check error log for additional information.', - $instance::class - ) + $instance::class, + ), ); } diff --git a/Engine/ApcuEngine.php b/Engine/ApcuEngine.php index 8cb611e94..43d580c68 100644 --- a/Engine/ApcuEngine.php +++ b/Engine/ApcuEngine.php @@ -145,7 +145,7 @@ public function clear(): bool if (class_exists(APCUIterator::class, false)) { $iterator = new APCUIterator( '/^' . preg_quote($this->_config['prefix'], '/') . '/', - APC_ITER_NONE + APC_ITER_NONE, ); apcu_delete($iterator); @@ -204,7 +204,7 @@ public function groups(): array $value = 1; if (apcu_store($group, $value) === false) { $this->warning( - sprintf('Failed to store key `%s` with value `%s` into APCu cache.', $group, $value) + sprintf('Failed to store key `%s` with value `%s` into APCu cache.', $group, $value), ); } $groups[$group] = $value; diff --git a/Engine/FileEngine.php b/Engine/FileEngine.php index 8ae5f4ab9..2e7761b82 100644 --- a/Engine/FileEngine.php +++ b/Engine/FileEngine.php @@ -243,11 +243,11 @@ public function clear(): bool $directory = new RecursiveDirectoryIterator( $this->_config['path'], - FilesystemIterator::SKIP_DOTS + FilesystemIterator::SKIP_DOTS, ); $iterator = new RecursiveIteratorIterator( $directory, - RecursiveIteratorIterator::SELF_FIRST + RecursiveIteratorIterator::SELF_FIRST, ); $cleared = []; /** @var \SplFileInfo $fileInfo */ @@ -394,7 +394,7 @@ protected function _setKey(string $key, bool $createKey = false): bool trigger_error(sprintf( 'Could not apply permission mask `%s` on cache file `%s`', $this->_File->getPathname(), - $this->_config['mask'] + $this->_config['mask'], ), E_USER_WARNING); } } @@ -423,7 +423,7 @@ protected function _active(): bool $this->_init = false; trigger_error(sprintf( '%s is not writable', - $this->_config['path'] + $this->_config['path'], ), E_USER_WARNING); } @@ -455,7 +455,7 @@ public function clearGroup(string $group): bool $directoryIterator = new RecursiveDirectoryIterator($this->_config['path']); $contents = new RecursiveIteratorIterator( $directoryIterator, - RecursiveIteratorIterator::CHILD_FIRST + RecursiveIteratorIterator::CHILD_FIRST, ); $filtered = new CallbackFilterIterator( $contents, @@ -471,9 +471,9 @@ function (SplFileInfo $current) use ($group, $prefix) { return str_contains( $current->getPathname(), - DIRECTORY_SEPARATOR . $group . DIRECTORY_SEPARATOR + DIRECTORY_SEPARATOR . $group . DIRECTORY_SEPARATOR, ); - } + }, ); /** @var \SplFileInfo $object */ foreach ($filtered as $object) { diff --git a/Engine/MemcachedEngine.php b/Engine/MemcachedEngine.php index 0fbeb427e..cb5f667e5 100644 --- a/Engine/MemcachedEngine.php +++ b/Engine/MemcachedEngine.php @@ -154,7 +154,7 @@ public function init(array $config = []): bool throw new InvalidArgumentException( 'Invalid cache configuration. Multiple persistent cache configurations are detected' . ' with different `servers` values. `servers` values for persistent cache configurations' . - ' must be the same when using the same persistence id.' + ' must be the same when using the same persistence id.', ); } } @@ -180,20 +180,20 @@ public function init(array $config = []): bool if (empty($this->_config['username']) && !empty($this->_config['login'])) { throw new InvalidArgumentException( - 'Please pass "username" instead of "login" for connecting to Memcached' + 'Please pass "username" instead of "login" for connecting to Memcached', ); } if ($this->_config['username'] !== null && $this->_config['password'] !== null) { if (!method_exists($this->_Memcached, 'setSaslAuthData')) { throw new InvalidArgumentException( - 'Memcached extension is not built with SASL support' + 'Memcached extension is not built with SASL support', ); } $this->_Memcached->setOption(Memcached::OPT_BINARY_PROTOCOL, true); $this->_Memcached->setSaslAuthData( $this->_config['username'], - $this->_config['password'] + $this->_config['password'], ); } @@ -214,7 +214,7 @@ protected function _setOptions(): void $serializer = strtolower($this->_config['serialize']); if (!isset($this->_serializers[$serializer])) { throw new InvalidArgumentException( - sprintf('`%s` is not a valid serializer engine for Memcached.', $serializer) + sprintf('`%s` is not a valid serializer engine for Memcached.', $serializer), ); } @@ -223,13 +223,13 @@ protected function _setOptions(): void !constant('Memcached::HAVE_' . strtoupper($serializer)) ) { throw new InvalidArgumentException( - sprintf('Memcached extension is not compiled with `%s` support.', $serializer) + sprintf('Memcached extension is not compiled with `%s` support.', $serializer), ); } $this->_Memcached->setOption( Memcached::OPT_SERIALIZER, - $this->_serializers[$serializer] + $this->_serializers[$serializer], ); // Check for Amazon ElastiCache instance @@ -242,7 +242,7 @@ protected function _setOptions(): void $this->_Memcached->setOption( Memcached::OPT_COMPRESSION, - (bool)$this->_config['compress'] + (bool)$this->_config['compress'], ); } diff --git a/Engine/RedisEngine.php b/Engine/RedisEngine.php index 68d92b3a6..b6ed5e53f 100644 --- a/Engine/RedisEngine.php +++ b/Engine/RedisEngine.php @@ -157,7 +157,7 @@ protected function _connectTransient(string $server, array $ssl): bool return $this->_Redis->connect( $server, (int)$this->_config['port'], - (int)$this->_config['timeout'] + (int)$this->_config['timeout'], ); } @@ -168,7 +168,7 @@ protected function _connectTransient(string $server, array $ssl): bool null, 0, 0.0, - ['ssl' => $ssl] + ['ssl' => $ssl], ); } @@ -189,7 +189,7 @@ protected function _connectPersistent(string $server, array $ssl): bool $server, (int)$this->_config['port'], (int)$this->_config['timeout'], - $persistentId + $persistentId, ); } @@ -200,7 +200,7 @@ protected function _connectPersistent(string $server, array $ssl): bool $persistentId, 0, 0.0, - ['ssl' => $ssl] + ['ssl' => $ssl], ); } From 6e8ca0ded7b885e8105bf2dbc7d6ab3ded7f38b6 Mon Sep 17 00:00:00 2001 From: ADmad Date: Sat, 28 Dec 2024 10:52:11 +0530 Subject: [PATCH 099/127] Add branch alias for 5.next. Update composer.json for sub packages. --- composer.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 8bab39996..e630be709 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ }, "require": { "php": ">=8.1", - "cakephp/core": "^5.1", + "cakephp/core": "^5.2", "psr/simple-cache": "^2.0 || ^3.0" }, "provide": { @@ -33,5 +33,7 @@ "psr-4": { "Cake\\Cache\\": "." } - } + }, + "minimum-stability": "dev", + "prefer-stable": true } From 1c6e33f505c65b773979a9b610cd3fc25404ca4d Mon Sep 17 00:00:00 2001 From: ADmad Date: Mon, 20 Jan 2025 19:32:22 +0530 Subject: [PATCH 100/127] Update dependency constraints for the split packages. This should allow using/testing the 5.next branch of the split packages. --- composer.json | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index e630be709..44562ce2a 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ }, "require": { "php": ">=8.1", - "cakephp/core": "^5.2", + "cakephp/core": "5.2.*@dev", "psr/simple-cache": "^2.0 || ^3.0" }, "provide": { @@ -34,6 +34,10 @@ "Cake\\Cache\\": "." } }, - "minimum-stability": "dev", - "prefer-stable": true + "prefer-stable": true, + "extra": { + "branch-alias": { + "dev-5.next": "5.2.x-dev" + } + } } From 08b30540f515f0b77db11b24f6900597793d5733 Mon Sep 17 00:00:00 2001 From: Joris Vaesen Date: Mon, 24 Mar 2025 15:13:53 +0100 Subject: [PATCH 101/127] Make NullEngine return the original keys with the default as other cache engines do --- Engine/NullEngine.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Engine/NullEngine.php b/Engine/NullEngine.php index bc2f06720..4fc45ee6a 100644 --- a/Engine/NullEngine.php +++ b/Engine/NullEngine.php @@ -63,7 +63,13 @@ public function get(string $key, mixed $default = null): mixed */ public function getMultiple(iterable $keys, mixed $default = null): iterable { - return []; + $result = []; + + foreach ($keys as $key) { + $result[$key] = $default; + } + + return $result; } /** From 5325620dba423abbf3f7c1ba9088276808eee2d1 Mon Sep 17 00:00:00 2001 From: Joris Vaesen Date: Sat, 29 Mar 2025 06:48:41 +0100 Subject: [PATCH 102/127] Treat null as a valid cache value on MemcachedEngine::getMultiple (#18253) --- Engine/MemcachedEngine.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Engine/MemcachedEngine.php b/Engine/MemcachedEngine.php index 7360dbf9e..3a6cf5172 100644 --- a/Engine/MemcachedEngine.php +++ b/Engine/MemcachedEngine.php @@ -367,7 +367,7 @@ public function getMultiple(iterable $keys, mixed $default = null): iterable $values = $this->_Memcached->getMulti($cacheKeys); $return = []; foreach ($cacheKeys as $original => $prefixed) { - $return[$original] = $values[$prefixed] ?? $default; + $return[$original] = array_key_exists($prefixed, $values) ? $values[$prefixed] : $default; } return $return; From ef014874ce4bf2ad9efcfeee34001547b55caf66 Mon Sep 17 00:00:00 2001 From: ADmad Date: Mon, 31 Mar 2025 11:26:24 +0530 Subject: [PATCH 103/127] Fix errors reported by phpstan --- Engine/MemcachedEngine.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Engine/MemcachedEngine.php b/Engine/MemcachedEngine.php index 3180629a4..fc6149f16 100644 --- a/Engine/MemcachedEngine.php +++ b/Engine/MemcachedEngine.php @@ -355,7 +355,7 @@ public function get(string $key, mixed $default = null): mixed * @param iterable $keys An array of identifiers for the data * @param mixed $default Default value to return for keys that do not exist. * @return iterable An array containing, for each of the given $keys, the cached data or - * false if cached data could not be retrieved. + * `$default` if cached data could not be retrieved. */ public function getMultiple(iterable $keys, mixed $default = null): iterable { @@ -365,6 +365,10 @@ public function getMultiple(iterable $keys, mixed $default = null): iterable } $values = $this->_Memcached->getMulti($cacheKeys); + if ($values === false) { + return array_fill_keys(array_keys($cacheKeys), $default); + } + $return = []; foreach ($cacheKeys as $original => $prefixed) { $return[$original] = array_key_exists($prefixed, $values) ? $values[$prefixed] : $default; From fd3abfa1400fb6a52f9003702b198b81655f5482 Mon Sep 17 00:00:00 2001 From: ADmad Date: Tue, 1 Apr 2025 00:37:16 +0530 Subject: [PATCH 104/127] Update composer branch aliases for split packages. (#18259) --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 44562ce2a..e978f708c 100644 --- a/composer.json +++ b/composer.json @@ -37,7 +37,7 @@ "prefer-stable": true, "extra": { "branch-alias": { - "dev-5.next": "5.2.x-dev" + "dev-5.x": "5.2.x-dev" } } } From efd05b80a77999101c2d3740de53ea104d8a5dc5 Mon Sep 17 00:00:00 2001 From: ADmad Date: Fri, 4 Apr 2025 20:04:44 +0530 Subject: [PATCH 105/127] Update split package dependencies for 5.3 (#18261) --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index e978f708c..66d91d025 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ }, "require": { "php": ">=8.1", - "cakephp/core": "5.2.*@dev", + "cakephp/core": "5.3.*@dev", "psr/simple-cache": "^2.0 || ^3.0" }, "provide": { @@ -37,7 +37,7 @@ "prefer-stable": true, "extra": { "branch-alias": { - "dev-5.x": "5.2.x-dev" + "dev-5.next": "5.3.x-dev" } } } From 26d854301ae5a13abf0a7c222a4f2df9d94035a5 Mon Sep 17 00:00:00 2001 From: mscherer Date: Sat, 5 Apr 2025 04:12:27 +0200 Subject: [PATCH 106/127] Fixed typos and cleanup. --- Engine/RedisEngine.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Engine/RedisEngine.php b/Engine/RedisEngine.php index b6ed5e53f..6490a0d36 100644 --- a/Engine/RedisEngine.php +++ b/Engine/RedisEngine.php @@ -433,7 +433,7 @@ public function clearGroup(string $group): bool * Serialize value for saving to Redis. * * This is needed instead of using Redis' in built serialization feature - * as it creates problems incrementing/decrementing intially set integer value. + * as it creates problems incrementing/decrementing initially set integer value. * * @param mixed $value Value to serialize. * @return string From cd95972a074e566e421b1290c69e6f55541e1e2b Mon Sep 17 00:00:00 2001 From: ADmad Date: Tue, 15 Apr 2025 21:22:17 +0530 Subject: [PATCH 107/127] Drop psalm --- Cache.php | 2 +- Engine/FileEngine.php | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Cache.php b/Cache.php index c69d9aa24..dab7c9be2 100644 --- a/Cache.php +++ b/Cache.php @@ -74,7 +74,7 @@ class Cache * class names. * * @var array - * @psalm-var array + * @phpstan-var array */ protected static array $_dsnClassMap = [ 'array' => Engine\ArrayEngine::class, diff --git a/Engine/FileEngine.php b/Engine/FileEngine.php index 2e7761b82..e38405f60 100644 --- a/Engine/FileEngine.php +++ b/Engine/FileEngine.php @@ -182,7 +182,6 @@ public function get(string $key, mixed $default = null): mixed $data = ''; $this->_File->next(); while ($this->_File->valid()) { - /** @psalm-suppress PossiblyInvalidOperand */ $data .= $this->_File->current(); $this->_File->next(); } @@ -374,7 +373,6 @@ protected function _setKey(string $key, bool $createKey = false): bool if (!$createKey && !$path->isFile()) { return false; } - /** @psalm-suppress TypeDoesNotContainType */ if ( !isset($this->_File) || $this->_File->getBasename() !== $key || From 20be4e1b41e9e3e21b9342df7766953263093694 Mon Sep 17 00:00:00 2001 From: Mark Scherer Date: Fri, 18 Apr 2025 22:31:51 +0200 Subject: [PATCH 108/127] Raise 5.3 PHP min to 8.2 (#18341) * Raise 5.3 PHP min to 8.2 * Drop phpunit 10. * Raise 5.3 PHP min to 8.2 in splits. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 66d91d025..bf9a8bf08 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ "source": "https://github.com/cakephp/cache" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "cakephp/core": "5.3.*@dev", "psr/simple-cache": "^2.0 || ^3.0" }, From ffa954ccc49b40bbffde258493bc035dd5477060 Mon Sep 17 00:00:00 2001 From: mscherer Date: Sat, 19 Apr 2025 13:52:51 +0200 Subject: [PATCH 109/127] Small cleanups and typo fixes. --- Engine/FileEngine.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Engine/FileEngine.php b/Engine/FileEngine.php index e38405f60..420abf68b 100644 --- a/Engine/FileEngine.php +++ b/Engine/FileEngine.php @@ -52,7 +52,7 @@ class FileEngine extends CacheEngine * - `lock` Used by FileCache. Should files be locked before writing to them? * - `mask` The mask used for created files * - `dirMask` The mask used for created folders - * - `path` Path to where cachefiles should be saved. Defaults to system's temp dir. + * - `path` Path to where cache files should be saved. Defaults to system's temp dir. * - `prefix` Prepended to all entries. Good for when you need to share a keyspace * with either another cache config or another application. * cache::gc from ever being called automatically. From b2e09daf6c00c73b9c4acdf437bcd4751db929ec Mon Sep 17 00:00:00 2001 From: ADmad Date: Wed, 23 Apr 2025 00:48:52 +0530 Subject: [PATCH 110/127] Update composer.json for split packages. This should fix running phpstan for the split packages --- composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.json b/composer.json index bf9a8bf08..5f7b7710d 100644 --- a/composer.json +++ b/composer.json @@ -34,6 +34,7 @@ "Cake\\Cache\\": "." } }, + "minimum-stability": "dev", "prefer-stable": true, "extra": { "branch-alias": { From fed6ad725bd8d1acef3a05a858b029469515ad0e Mon Sep 17 00:00:00 2001 From: Mark Scherer Date: Thu, 8 May 2025 06:26:53 +0200 Subject: [PATCH 111/127] Allow flushDb() usage (#18613) * Allow flushDb() usage * Fix tests. * Make option name more explicit and fix tests. * Add test coverage for clearUsesFlushDb * Clear configs between tests * Fix mistakes in tests --------- Co-authored-by: Mark Story --- Engine/RedisEngine.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Engine/RedisEngine.php b/Engine/RedisEngine.php index 6490a0d36..9f5bd8d48 100644 --- a/Engine/RedisEngine.php +++ b/Engine/RedisEngine.php @@ -53,6 +53,9 @@ class RedisEngine extends CacheEngine * - `server` URL or IP to the Redis server host. * - `timeout` timeout in seconds (float). * - `unix_socket` Path to the unix socket file (default: false) + * - `clearUsesFlushDb` Enable clear() and clearBlocking() to use FLUSHDB. This will be + * faster than standard clear()/clearBlocking() but will ignore prefixes and will + * cause dataloss if other applications are sharing a redis database. * * @var array */ @@ -70,6 +73,7 @@ class RedisEngine extends CacheEngine 'timeout' => 0, 'unix_socket' => false, 'scanCount' => 10, + 'clearUsesFlushDb' => false, ]; /** @@ -320,6 +324,12 @@ public function deleteAsync(string $key): bool */ public function clear(): bool { + if ($this->getConfig('clearUsesFlushDb')) { + $this->_Redis->flushDB(false); + + return true; + } + $this->_Redis->setOption(Redis::OPT_SCAN, (string)Redis::SCAN_RETRY); $isAllDeleted = true; @@ -351,6 +361,12 @@ public function clear(): bool */ public function clearBlocking(): bool { + if ($this->getConfig('clearUsesFlushDb')) { + $this->_Redis->flushDB(true); + + return true; + } + $this->_Redis->setOption(Redis::OPT_SCAN, (string)Redis::SCAN_RETRY); $isAllDeleted = true; From 2b7c1aec5a7103fea66f3087368af1ae5ed70aac Mon Sep 17 00:00:00 2001 From: Nicos Panayides Date: Thu, 5 Jun 2025 15:04:18 +0300 Subject: [PATCH 112/127] Use the correct operations for clear and clearBlocking (#18721) * Use the correct operations for clear and clearBlocking * Use the non-deprecated del function * Fix incorrect function comment --- Engine/RedisEngine.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Engine/RedisEngine.php b/Engine/RedisEngine.php index 9f5bd8d48..8e4fb4af1 100644 --- a/Engine/RedisEngine.php +++ b/Engine/RedisEngine.php @@ -344,7 +344,7 @@ public function clear(): bool } foreach ($keys as $key) { - $isDeleted = ((int)$this->_Redis->del($key) > 0); + $isDeleted = ((int)$this->_Redis->unlink($key) > 0); $isAllDeleted = $isAllDeleted && $isDeleted; } } @@ -355,8 +355,6 @@ public function clear(): bool /** * Delete all keys from the cache by a blocking operation * - * Faster than clear() using unlink method. - * * @return bool True if the cache was successfully cleared, false otherwise */ public function clearBlocking(): bool @@ -381,7 +379,7 @@ public function clearBlocking(): bool } foreach ($keys as $key) { - $isDeleted = ((int)$this->_Redis->unlink($key) > 0); + $isDeleted = ((int)$this->_Redis->del($key) > 0); $isAllDeleted = $isAllDeleted && $isDeleted; } } From ee5081f950aaf6233023f96cb98ecad674134a49 Mon Sep 17 00:00:00 2001 From: Felix Kempf Date: Tue, 24 Jun 2025 21:40:17 +0200 Subject: [PATCH 113/127] Add lost DocBlock line to FileEngine.php (#18757) * Add lost DocBlock line to FileEngine.php * Fix docblock merge issue. --------- Co-authored-by: Mark Scherer --- Engine/FileEngine.php | 1 - 1 file changed, 1 deletion(-) diff --git a/Engine/FileEngine.php b/Engine/FileEngine.php index 420abf68b..2e20d7952 100644 --- a/Engine/FileEngine.php +++ b/Engine/FileEngine.php @@ -55,7 +55,6 @@ class FileEngine extends CacheEngine * - `path` Path to where cache files should be saved. Defaults to system's temp dir. * - `prefix` Prepended to all entries. Good for when you need to share a keyspace * with either another cache config or another application. - * cache::gc from ever being called automatically. * - `serialize` Should cache objects be serialized first. * * @var array From e4e023a3bd796884efc5dfa9177a7eddbb510ea4 Mon Sep 17 00:00:00 2001 From: Mark Scherer Date: Sun, 20 Jul 2025 04:02:49 +0200 Subject: [PATCH 114/127] Fix some spelling and broken code snippets. (#18791) --- Engine/MemcachedEngine.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Engine/MemcachedEngine.php b/Engine/MemcachedEngine.php index fc6149f16..6a2d19ec1 100644 --- a/Engine/MemcachedEngine.php +++ b/Engine/MemcachedEngine.php @@ -54,7 +54,7 @@ class MemcachedEngine extends CacheEngine * - `prefix` Prepended to all entries. Good for when you need to share a keyspace * with either another cache config or another application. * - `serialize` The serializer engine used to serialize data. Available engines are 'php', - * 'igbinary' and 'json'. Beside 'php', the memcached extension must be compiled with the + * 'igbinary' and 'json'. Besides 'php', the memcached extension must be compiled with the * appropriate serializer support. * - `servers` String or array of memcached servers. If an array MemcacheEngine will use * them as a pool. From f88a13e03a924ef9c447c924870f2f6f517dee3a Mon Sep 17 00:00:00 2001 From: Juhani Aronen Date: Mon, 11 Aug 2025 14:00:41 +0300 Subject: [PATCH 115/127] Merge pull request #17982 - Redis cluster support --- Engine/RedisEngine.php | 163 +++++++++++++++++++++++++++++++++++------ 1 file changed, 139 insertions(+), 24 deletions(-) diff --git a/Engine/RedisEngine.php b/Engine/RedisEngine.php index 8e4fb4af1..0626f5748 100644 --- a/Engine/RedisEngine.php +++ b/Engine/RedisEngine.php @@ -22,6 +22,8 @@ use Cake\Log\Log; use DateInterval; use Redis; +use RedisCluster; +use RedisClusterException; use RedisException; /** @@ -34,11 +36,12 @@ class RedisEngine extends CacheEngine * * @var \Redis */ - protected Redis $_Redis; + protected Redis|RedisCluster $_Redis; /** * The default config used unless overridden by runtime configuration * + * - `clusterName` Redis cluster name * - `database` database number to use for connection. * - `duration` Specify how long items in this cache configuration last. * - `groups` List of groups or 'tags' associated to every key stored in this config. @@ -53,6 +56,15 @@ class RedisEngine extends CacheEngine * - `server` URL or IP to the Redis server host. * - `timeout` timeout in seconds (float). * - `unix_socket` Path to the unix socket file (default: false) + * - `readTimeout` Read timeout in seconds (float). + * - `nodes` When using redis-cluster, the URL or IP addresses of the + * Redis cluster nodes. + * Format: an array of strings in the form `:`, like: + * [ + * ':', + * ':', + * ':', + * ] * - `clearUsesFlushDb` Enable clear() and clearBlocking() to use FLUSHDB. This will be * faster than standard clear()/clearBlocking() but will ignore prefixes and will * cause dataloss if other applications are sharing a redis database. @@ -60,6 +72,7 @@ class RedisEngine extends CacheEngine * @var array */ protected array $_defaultConfig = [ + 'clusterName' => null, 'database' => 0, 'duration' => 3600, 'groups' => [], @@ -73,6 +86,8 @@ class RedisEngine extends CacheEngine 'timeout' => 0, 'unix_socket' => false, 'scanCount' => 10, + 'readTimeout' => 0, + 'nodes' => [], 'clearUsesFlushDb' => false, ]; @@ -105,6 +120,74 @@ public function init(array $config = []): bool * @return bool True if Redis server was connected */ protected function _connect(): bool + { + if (!empty($this->_config['nodes'])) { + return $this->connectRedisCluster(); + } + + return $this->connectRedis(); + } + + /** + * Connects to a Redis cluster server + * + * @return bool True if Redis server was connected + */ + protected function connectRedisCluster(): bool + { + $connected = false; + + // @codeCoverageIgnoreStart + $ssl = []; + if ($this->_config['tls']) { + $map = [ + 'ssl_ca' => 'cafile', + 'ssl_key' => 'local_pk', + 'ssl_cert' => 'local_cert', + 'verify_peer' => 'verify_peer', + 'verify_peer_name' => 'verify_peer_name', + 'allow_self_signed' => 'allow_self_signed', + ]; + + foreach ($map as $configKey => $sslOption) { + if (array_key_exists($configKey, $this->_config)) { + $ssl[$sslOption] = $this->_config[$configKey]; + } + } + } + // @codeCoverageIgnoreEnd + + try { + $this->_Redis = new RedisCluster( + $this->_config['clusterName'], + $this->_config['nodes'], + (float)$this->_config['timeout'], + (float)$this->_config['readTimeout'], + $this->_config['persistent'], + $this->_config['password'], + $this->_config['tls'] ? ['ssl' => $ssl] : null, // @codeCoverageIgnore + ); + + $connected = true; + } catch (RedisClusterException $e) { + $connected = false; + + // @codeCoverageIgnoreStart + if (class_exists(Log::class)) { + Log::error('RedisEngine could not connect to the redis cluster. Got error: ' . $e->getMessage()); + } + // @codeCoverageIgnoreEnd + } + + return $connected; + } + + /** + * Connects to a Redis server + * + * @return bool True if Redis server was connected + */ + protected function connectRedis(): bool { $tls = $this->_config['tls'] === true ? 'tls://' : ''; @@ -137,6 +220,7 @@ protected function _connect(): bool return false; } + if ($return && $this->_config['password']) { $return = $this->_Redis->auth($this->_config['password']); } @@ -324,7 +408,7 @@ public function deleteAsync(string $key): bool */ public function clear(): bool { - if ($this->getConfig('clearUsesFlushDb')) { + if ($this->getConfig('clearUsesFlushDb') && $this->_Redis instanceof Redis) { $this->_Redis->flushDB(false); return true; @@ -333,19 +417,25 @@ public function clear(): bool $this->_Redis->setOption(Redis::OPT_SCAN, (string)Redis::SCAN_RETRY); $isAllDeleted = true; - $iterator = null; $pattern = $this->_config['prefix'] . '*'; + $scanCount = (int)$this->_config['scanCount']; - while (true) { - $keys = $this->_Redis->scan($iterator, $pattern, (int)$this->_config['scanCount']); - - if ($keys === false) { - break; - } + // Set scan option only if using a Redis instance (not RedisCluster) + if ($this->_Redis instanceof Redis) { + $this->_Redis->setOption(Redis::OPT_SCAN, Redis::SCAN_RETRY); + } - foreach ($keys as $key) { - $isDeleted = ((int)$this->_Redis->unlink($key) > 0); - $isAllDeleted = $isAllDeleted && $isDeleted; + $nodes = $this->_Redis instanceof RedisCluster + ? $this->_Redis->_masters() + : [null]; + + foreach ($nodes as $node) { + $it = null; + while (($keys = $this->scanKeys($it, $pattern, $scanCount, $node)) !== false) { + foreach ($keys as $key) { + $isDeleted = ((int)$this->_Redis->unlink($key) > 0); + $isAllDeleted = $isAllDeleted && $isDeleted; + } } } @@ -359,8 +449,8 @@ public function clear(): bool */ public function clearBlocking(): bool { - if ($this->getConfig('clearUsesFlushDb')) { - $this->_Redis->flushDB(true); + if ($this->getConfig('clearUsesFlushDb') && $this->_Redis instanceof Redis) { + $this->_Redis->flushDB(false); return true; } @@ -368,19 +458,26 @@ public function clearBlocking(): bool $this->_Redis->setOption(Redis::OPT_SCAN, (string)Redis::SCAN_RETRY); $isAllDeleted = true; - $iterator = null; $pattern = $this->_config['prefix'] . '*'; + $scanCount = (int)$this->_config['scanCount']; - while (true) { - $keys = $this->_Redis->scan($iterator, $pattern, (int)$this->_config['scanCount']); - - if ($keys === false) { - break; - } + // Set scan option for Redis instance (not supported in RedisCluster) + if ($this->_Redis instanceof Redis) { + $this->_Redis->setOption(Redis::OPT_SCAN, (string)Redis::SCAN_RETRY); + } - foreach ($keys as $key) { - $isDeleted = ((int)$this->_Redis->del($key) > 0); - $isAllDeleted = $isAllDeleted && $isDeleted; + $nodes = $this->_Redis instanceof RedisCluster + ? $this->_Redis->_masters() + : [null]; + + foreach ($nodes as $node) { + $it = null; + while (($keys = $this->scanKeys($it, $pattern, $scanCount, $node)) !== false) { + foreach ($keys as $key) { + // Blocking delete + $isDeleted = ((int)$this->_Redis->del($key) > 0); + $isAllDeleted = $isAllDeleted && $isDeleted; + } } } @@ -487,6 +584,24 @@ protected function _createRedisInstance(): Redis return new Redis(); } + /** + * Unifies Redis and RedisCluster scan() calls. + * + * @param int|null $it Passed by reference cursor + * @param string $pattern + * @param int $count + * @param array|string|null $node Master address for cluster, or null for single node + * @return array|false + */ + private function scanKeys(?int &$it, string $pattern, int $count, string|array|null $node = null): array|false + { + if ($this->_Redis instanceof RedisCluster) { + return $this->_Redis->scan($it, $node, $pattern, $count); + } + + return $this->_Redis->scan($it, $pattern, $count); + } + /** * Disconnects from the redis server */ From 6d1291db221f95f3cd85639d28cb187daacce2aa Mon Sep 17 00:00:00 2001 From: Nicos Panayides Date: Wed, 20 Aug 2025 20:49:32 +0300 Subject: [PATCH 116/127] Redis cluster improvements (#18828) * Simplify scan and encapsulate flushDB and support it in cluster mode as well * Use cluster if clusterName is set as well. * Add support for failover modes * Fix scan for cluster mode * Fix phpstan baseline * Test fixes * Only detect redis socket once for tests. Speeds up windows tests. Fix test * Only check cluster nodes once in redis cluster test as well. Fix closing of invalid socket * Fix phpcs error. * Support RedisCluster int constants for failover in addition to the strings * Use async flushDB on clear for consistency * Override has() to avoid fetching and unserializing values only to check if they exist. * Move the error messages for missing nodes from stdout to skipIf reason * Ensure exists returns an int before using it. phpcs fix. * Ensure we always pass a string to skipIf message * Fix error message * Added test for creating a redis cluster cache with named configuration * Fix test configuration * Set default nodes to null so that seeds from named configuration work * Restore node as empty array because null is not accepted even if the documentation says otherwise. * Error when using clusterName without nodes --- Engine/RedisEngine.php | 151 ++++++++++++++++++++++++++--------------- 1 file changed, 96 insertions(+), 55 deletions(-) diff --git a/Engine/RedisEngine.php b/Engine/RedisEngine.php index 0626f5748..509f95018 100644 --- a/Engine/RedisEngine.php +++ b/Engine/RedisEngine.php @@ -21,6 +21,7 @@ use Cake\Core\Exception\CakeException; use Cake\Log\Log; use DateInterval; +use Generator; use Redis; use RedisCluster; use RedisClusterException; @@ -65,6 +66,7 @@ class RedisEngine extends CacheEngine * ':', * ':', * ] + * - `failover` Failover mode (distribute,distribute_slaves,error,none). Cluster mode only. * - `clearUsesFlushDb` Enable clear() and clearBlocking() to use FLUSHDB. This will be * faster than standard clear()/clearBlocking() but will ignore prefixes and will * cause dataloss if other applications are sharing a redis database. @@ -88,6 +90,7 @@ class RedisEngine extends CacheEngine 'scanCount' => 10, 'readTimeout' => 0, 'nodes' => [], + 'failover' => null, 'clearUsesFlushDb' => false, ]; @@ -121,7 +124,7 @@ public function init(array $config = []): bool */ protected function _connect(): bool { - if (!empty($this->_config['nodes'])) { + if (!empty($this->_config['nodes']) || !empty($this->_config['clusterName'])) { return $this->connectRedisCluster(); } @@ -137,6 +140,16 @@ protected function connectRedisCluster(): bool { $connected = false; + if (empty($this->_config['nodes'])) { + // @codeCoverageIgnoreStart + if (class_exists(Log::class)) { + Log::error('RedisEngine requires one or more nodes in cluster mode'); + } + // @codeCoverageIgnoreEnd + + return false; + } + // @codeCoverageIgnoreStart $ssl = []; if ($this->_config['tls']) { @@ -179,6 +192,18 @@ protected function connectRedisCluster(): bool // @codeCoverageIgnoreEnd } + $failover = match ($this->_config['failover']) { + RedisCluster::FAILOVER_DISTRIBUTE, 'distribute' => RedisCluster::FAILOVER_DISTRIBUTE, + RedisCluster::FAILOVER_DISTRIBUTE_SLAVES, 'distribute_slaves' => RedisCluster::FAILOVER_DISTRIBUTE_SLAVES, + RedisCluster::FAILOVER_ERROR, 'error' => RedisCluster::FAILOVER_ERROR, + RedisCluster::FAILOVER_NONE, 'none' => RedisCluster::FAILOVER_NONE, + default => null, + }; + + if ($failover !== null) { + $this->_Redis->setOption(RedisCluster::OPT_SLAVE_FAILOVER, $failover); + } + return $connected; } @@ -333,6 +358,16 @@ public function get(string $key, mixed $default = null): mixed return $this->unserialize($value); } + /** + * @inheritDoc + */ + public function has(string $key): bool + { + $res = $this->_Redis->exists($this->_key($key)); + + return is_int($res) ? $res > 0 : $res === true; + } + /** * Increments the value of an integer cached key & update the expiry time * @@ -408,35 +443,18 @@ public function deleteAsync(string $key): bool */ public function clear(): bool { - if ($this->getConfig('clearUsesFlushDb') && $this->_Redis instanceof Redis) { - $this->_Redis->flushDB(false); + if ($this->getConfig('clearUsesFlushDb')) { + $this->flushDB(true); return true; } - $this->_Redis->setOption(Redis::OPT_SCAN, (string)Redis::SCAN_RETRY); - $isAllDeleted = true; $pattern = $this->_config['prefix'] . '*'; - $scanCount = (int)$this->_config['scanCount']; - // Set scan option only if using a Redis instance (not RedisCluster) - if ($this->_Redis instanceof Redis) { - $this->_Redis->setOption(Redis::OPT_SCAN, Redis::SCAN_RETRY); - } - - $nodes = $this->_Redis instanceof RedisCluster - ? $this->_Redis->_masters() - : [null]; - - foreach ($nodes as $node) { - $it = null; - while (($keys = $this->scanKeys($it, $pattern, $scanCount, $node)) !== false) { - foreach ($keys as $key) { - $isDeleted = ((int)$this->_Redis->unlink($key) > 0); - $isAllDeleted = $isAllDeleted && $isDeleted; - } - } + foreach ($this->scanKeys($pattern) as $key) { + $isDeleted = ((int)$this->_Redis->unlink($key) > 0); + $isAllDeleted = $isAllDeleted && $isDeleted; } return $isAllDeleted; @@ -449,36 +467,19 @@ public function clear(): bool */ public function clearBlocking(): bool { - if ($this->getConfig('clearUsesFlushDb') && $this->_Redis instanceof Redis) { - $this->_Redis->flushDB(false); + if ($this->getConfig('clearUsesFlushDb')) { + $this->flushDB(false); return true; } - $this->_Redis->setOption(Redis::OPT_SCAN, (string)Redis::SCAN_RETRY); - $isAllDeleted = true; $pattern = $this->_config['prefix'] . '*'; - $scanCount = (int)$this->_config['scanCount']; - // Set scan option for Redis instance (not supported in RedisCluster) - if ($this->_Redis instanceof Redis) { - $this->_Redis->setOption(Redis::OPT_SCAN, (string)Redis::SCAN_RETRY); - } - - $nodes = $this->_Redis instanceof RedisCluster - ? $this->_Redis->_masters() - : [null]; - - foreach ($nodes as $node) { - $it = null; - while (($keys = $this->scanKeys($it, $pattern, $scanCount, $node)) !== false) { - foreach ($keys as $key) { - // Blocking delete - $isDeleted = ((int)$this->_Redis->del($key) > 0); - $isAllDeleted = $isAllDeleted && $isDeleted; - } - } + foreach ($this->scanKeys($pattern) as $key) { + // Blocking delete + $isDeleted = ((int)$this->_Redis->del($key) > 0); + $isAllDeleted = $isAllDeleted && $isDeleted; } return $isAllDeleted; @@ -585,21 +586,61 @@ protected function _createRedisInstance(): Redis } /** - * Unifies Redis and RedisCluster scan() calls. + * Unifies Redis and RedisCluster scan() calls and simplifies its use. * - * @param int|null $it Passed by reference cursor - * @param string $pattern - * @param int $count - * @param array|string|null $node Master address for cluster, or null for single node - * @return array|false + * @param string $pattern Pattern to scan + * @return \Generator */ - private function scanKeys(?int &$it, string $pattern, int $count, string|array|null $node = null): array|false + private function scanKeys(string $pattern): Generator { + $this->_Redis->setOption(Redis::OPT_SCAN, (string)Redis::SCAN_RETRY); + if ($this->_Redis instanceof RedisCluster) { - return $this->_Redis->scan($it, $node, $pattern, $count); + foreach ($this->_Redis->_masters() as $node) { + $iterator = null; + while (true) { + // @phpstan-ignore arguments.count, argument.type + $keys = $this->_Redis->scan($iterator, $node, $pattern, (int)$this->_config['scanCount']); + if ($keys === false) { + break; + } + + foreach ($keys as $key) { + yield $key; + } + } + } + } else { + $iterator = null; + while (true) { + $keys = $this->_Redis->scan($iterator, $pattern, (int)$this->_config['scanCount']); + if ($keys === false) { + break; + } + + foreach ($keys as $key) { + yield $key; + } + } } + } - return $this->_Redis->scan($it, $pattern, $count); + /** + * Flushes DB + * + * @param bool $async Whether to use asynchronous mode + * @return void + */ + private function flushDB(bool $async): void + { + if ($this->_Redis instanceof RedisCluster) { + foreach ($this->_Redis->_masters() as $node) { + // @phpstan-ignore arguments.count + $this->_Redis->flushDB($node, $async); + } + } else { + $this->_Redis->flushDB($async); + } } /** From 57765eeb028344be6e6329939f455343b24dc9f4 Mon Sep 17 00:00:00 2001 From: ADmad Date: Sun, 31 Aug 2025 22:40:59 +0530 Subject: [PATCH 117/127] Use null coalescing operator --- Engine/ArrayEngine.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Engine/ArrayEngine.php b/Engine/ArrayEngine.php index 6b1f2500c..b194e6fdd 100644 --- a/Engine/ArrayEngine.php +++ b/Engine/ArrayEngine.php @@ -160,9 +160,7 @@ public function groups(): array $result = []; foreach ($this->_config['groups'] as $group) { $key = $this->_config['prefix'] . $group; - if (!isset($this->data[$key])) { - $this->data[$key] = ['exp' => PHP_INT_MAX, 'val' => 1]; - } + $this->data[$key] ??= ['exp' => PHP_INT_MAX, 'val' => 1]; $value = $this->data[$key]['val']; $result[] = $group . $value; } From 3ba88939485a3c9f4018b8a42d591fa79ed20faa Mon Sep 17 00:00:00 2001 From: ADmad Date: Tue, 16 Sep 2025 18:04:18 +0530 Subject: [PATCH 118/127] Code cleanup --- Cache.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cache.php b/Cache.php index dab7c9be2..1b01bd65d 100644 --- a/Cache.php +++ b/Cache.php @@ -209,13 +209,13 @@ public static function pool(string $config): CacheInterface&CacheEngineInterface $registry = static::getRegistry(); - if (isset($registry->{$config})) { - return $registry->{$config}; + if ($registry->has($config)) { + return $registry->get($config); } static::_buildEngine($config); - return $registry->{$config}; + return $registry->get($config); } /** From 508f24207ac278c79be09b2e1c07f07792fa8f90 Mon Sep 17 00:00:00 2001 From: mscherer Date: Tue, 23 Sep 2025 14:32:57 +0200 Subject: [PATCH 119/127] Fix redis bug with initialize --- Engine/RedisEngine.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Engine/RedisEngine.php b/Engine/RedisEngine.php index 8e4fb4af1..b389ce870 100644 --- a/Engine/RedisEngine.php +++ b/Engine/RedisEngine.php @@ -492,7 +492,7 @@ protected function _createRedisInstance(): Redis */ public function __destruct() { - if (empty($this->_config['persistent'])) { + if (isset($this->_Redis) && empty($this->_config['persistent'])) { $this->_Redis->close(); } } From dca921805e512388856f9cc2c199bbb79d2abf51 Mon Sep 17 00:00:00 2001 From: Mark Scherer Date: Wed, 1 Oct 2025 20:43:27 +0200 Subject: [PATCH 120/127] Fix up permissions via umask. (#18940) --- Engine/FileEngine.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Engine/FileEngine.php b/Engine/FileEngine.php index 2e20d7952..a74385bf8 100644 --- a/Engine/FileEngine.php +++ b/Engine/FileEngine.php @@ -64,7 +64,7 @@ class FileEngine extends CacheEngine 'groups' => [], 'lock' => true, 'mask' => 0664, - 'dirMask' => 0770, + 'dirMask' => 0777, 'path' => null, 'prefix' => 'cake_', 'serialize' => true, @@ -364,7 +364,7 @@ protected function _setKey(string $key, bool $createKey = false): bool $dir = $this->_config['path'] . $groups; if (!is_dir($dir)) { - mkdir($dir, $this->_config['dirMask'], true); + mkdir($dir, $this->_config['dirMask'] ^ umask(), true); } $path = new SplFileInfo($dir . $key); @@ -411,7 +411,7 @@ protected function _active(): bool $success = true; if (!is_dir($path)) { // phpcs:disable - $success = @mkdir($path, $this->_config['dirMask'], true); + $success = @mkdir($path, $this->_config['dirMask'] ^ umask(), true); // phpcs:enable } From 6bc68d858aa36a8d6b1df01ba6c194dae8fd61c4 Mon Sep 17 00:00:00 2001 From: Kevin Pfeifer Date: Mon, 20 Oct 2025 18:31:03 +0200 Subject: [PATCH 121/127] add events for the caching system (#18956) add events for the caching system --- CacheEngine.php | 27 +++++- Engine/ApcuEngine.php | 84 +++++++++++++++++-- Engine/ArrayEngine.php | 57 ++++++++++++- Engine/FileEngine.php | 46 ++++++++++- Engine/MemcachedEngine.php | 99 ++++++++++++++++++++-- Engine/RedisEngine.php | 105 ++++++++++++++++++++++-- Event/CacheAfterAddEvent.php | 103 +++++++++++++++++++++++ Event/CacheAfterDecrementEvent.php | 123 ++++++++++++++++++++++++++++ Event/CacheAfterDeleteEvent.php | 89 ++++++++++++++++++++ Event/CacheAfterGetEvent.php | 103 +++++++++++++++++++++++ Event/CacheAfterIncrementEvent.php | 123 ++++++++++++++++++++++++++++ Event/CacheAfterSetEvent.php | 103 +++++++++++++++++++++++ Event/CacheBeforeAddEvent.php | 71 ++++++++++++++++ Event/CacheBeforeDecrementEvent.php | 75 +++++++++++++++++ Event/CacheBeforeDeleteEvent.php | 57 +++++++++++++ Event/CacheBeforeGetEvent.php | 71 ++++++++++++++++ Event/CacheBeforeIncrementEvent.php | 75 +++++++++++++++++ Event/CacheBeforeSetEvent.php | 86 +++++++++++++++++++ Event/CacheClearedEvent.php | 29 +++++++ Event/CacheGroupClearEvent.php | 59 +++++++++++++ composer.json | 1 + 21 files changed, 1562 insertions(+), 24 deletions(-) create mode 100644 Event/CacheAfterAddEvent.php create mode 100644 Event/CacheAfterDecrementEvent.php create mode 100644 Event/CacheAfterDeleteEvent.php create mode 100644 Event/CacheAfterGetEvent.php create mode 100644 Event/CacheAfterIncrementEvent.php create mode 100644 Event/CacheAfterSetEvent.php create mode 100644 Event/CacheBeforeAddEvent.php create mode 100644 Event/CacheBeforeDecrementEvent.php create mode 100644 Event/CacheBeforeDeleteEvent.php create mode 100644 Event/CacheBeforeGetEvent.php create mode 100644 Event/CacheBeforeIncrementEvent.php create mode 100644 Event/CacheBeforeSetEvent.php create mode 100644 Event/CacheClearedEvent.php create mode 100644 Event/CacheGroupClearEvent.php diff --git a/CacheEngine.php b/CacheEngine.php index 22a180fc0..9569cd1c0 100644 --- a/CacheEngine.php +++ b/CacheEngine.php @@ -16,8 +16,12 @@ */ namespace Cake\Cache; +use Cake\Cache\Event\CacheAfterAddEvent; +use Cake\Cache\Event\CacheBeforeAddEvent; use Cake\Cache\Exception\InvalidArgumentException; use Cake\Core\InstanceConfigTrait; +use Cake\Event\EventDispatcherInterface; +use Cake\Event\EventDispatcherTrait; use DateInterval; use DateTime; use Psr\SimpleCache\CacheInterface; @@ -26,8 +30,12 @@ /** * Storage engine for CakePHP caching */ -abstract class CacheEngine implements CacheInterface, CacheEngineInterface +abstract class CacheEngine implements CacheInterface, CacheEngineInterface, EventDispatcherInterface { + /** + * @use \Cake\Event\EventDispatcherTrait<\Cake\Cache\CacheEngine> + */ + use EventDispatcherTrait; use InstanceConfigTrait; /** @@ -296,9 +304,24 @@ abstract public function clear(): bool; public function add(string $key, mixed $value): bool { $cachedValue = $this->get($key); + $prefixedKey = $this->_key($key); + + $this->_eventClass = CacheBeforeAddEvent::class; + $this->dispatchEvent(CacheBeforeAddEvent::NAME, ['key' => $prefixedKey, 'value' => $value]); + if ($cachedValue === null) { - return $this->set($key, $value); + $success = $this->set($key, $value); + $this->_eventClass = CacheAfterAddEvent::class; + $this->dispatchEvent(CacheAfterAddEvent::NAME, [ + 'key' => $prefixedKey, 'value' => $value, 'success' => $success, + ]); + + return $success; } + $this->_eventClass = CacheAfterAddEvent::class; + $this->dispatchEvent(CacheAfterAddEvent::NAME, [ + 'key' => $prefixedKey, 'value' => $value, 'success' => false, + ]); return false; } diff --git a/Engine/ApcuEngine.php b/Engine/ApcuEngine.php index 43d580c68..c55394da2 100644 --- a/Engine/ApcuEngine.php +++ b/Engine/ApcuEngine.php @@ -18,6 +18,20 @@ use APCUIterator; use Cake\Cache\CacheEngine; +use Cake\Cache\Event\CacheAfterAddEvent; +use Cake\Cache\Event\CacheAfterDecrementEvent; +use Cake\Cache\Event\CacheAfterDeleteEvent; +use Cake\Cache\Event\CacheAfterGetEvent; +use Cake\Cache\Event\CacheAfterIncrementEvent; +use Cake\Cache\Event\CacheAfterSetEvent; +use Cake\Cache\Event\CacheBeforeAddEvent; +use Cake\Cache\Event\CacheBeforeDecrementEvent; +use Cake\Cache\Event\CacheBeforeDeleteEvent; +use Cake\Cache\Event\CacheBeforeGetEvent; +use Cake\Cache\Event\CacheBeforeIncrementEvent; +use Cake\Cache\Event\CacheBeforeSetEvent; +use Cake\Cache\Event\CacheClearedEvent; +use Cake\Cache\Event\CacheGroupClearEvent; use Cake\Core\Exception\CakeException; use DateInterval; @@ -67,7 +81,17 @@ public function set(string $key, mixed $value, DateInterval|int|null $ttl = null $key = $this->_key($key); $duration = $this->duration($ttl); - return apcu_store($key, $value, $duration); + $this->_eventClass = CacheBeforeSetEvent::class; + $this->dispatchEvent(CacheBeforeSetEvent::NAME, ['key' => $key, 'value' => $value, 'ttl' => $ttl]); + + $success = apcu_store($key, $value, $duration); + + $this->_eventClass = CacheAfterSetEvent::class; + $this->dispatchEvent(CacheAfterSetEvent::NAME, [ + 'key' => $key, 'value' => $value, 'success' => $success, + ]); + + return $success; } /** @@ -81,7 +105,14 @@ public function set(string $key, mixed $value, DateInterval|int|null $ttl = null */ public function get(string $key, mixed $default = null): mixed { - $value = apcu_fetch($this->_key($key), $success); + $key = $this->_key($key); + $this->_eventClass = CacheBeforeGetEvent::class; + $this->dispatchEvent(CacheBeforeGetEvent::NAME, ['key' => $key, 'default' => $default]); + + $value = apcu_fetch($key, $success); + + $this->_eventClass = CacheAfterGetEvent::class; + $this->dispatchEvent(CacheAfterGetEvent::NAME, ['key' => $key, 'value' => $value, 'success' => $success]); if ($success === false) { return $default; } @@ -100,8 +131,17 @@ public function get(string $key, mixed $default = null): mixed public function increment(string $key, int $offset = 1): int|false { $key = $this->_key($key); + $this->_eventClass = CacheBeforeIncrementEvent::class; + $this->dispatchEvent(CacheBeforeIncrementEvent::NAME, ['key' => $key, 'offset' => $offset]); + + $value = apcu_inc($key, $offset); - return apcu_inc($key, $offset); + $this->_eventClass = CacheAfterIncrementEvent::class; + $this->dispatchEvent(CacheAfterIncrementEvent::NAME, [ + 'key' => $key, 'offset' => $offset, 'success' => $value !== false, 'value' => $value, + ]); + + return $value; } /** @@ -115,8 +155,17 @@ public function increment(string $key, int $offset = 1): int|false public function decrement(string $key, int $offset = 1): int|false { $key = $this->_key($key); + $this->_eventClass = CacheBeforeDecrementEvent::class; + $this->dispatchEvent(CacheBeforeDecrementEvent::NAME, ['key' => $key, 'offset' => $offset]); - return apcu_dec($key, $offset); + $result = apcu_dec($key, $offset); + + $this->_eventClass = CacheAfterDecrementEvent::class; + $this->dispatchEvent(CacheAfterDecrementEvent::NAME, [ + 'key' => $key, 'offset' => $offset, 'success' => $result !== false, 'value' => $result, + ]); + + return $result; } /** @@ -129,8 +178,15 @@ public function decrement(string $key, int $offset = 1): int|false public function delete(string $key): bool { $key = $this->_key($key); + $this->_eventClass = CacheBeforeDeleteEvent::class; + $this->dispatchEvent(CacheBeforeDeleteEvent::NAME, ['key' => $key]); + + $result = apcu_delete($key); + + $this->_eventClass = CacheAfterDeleteEvent::class; + $this->dispatchEvent(CacheAfterDeleteEvent::NAME, ['key' => $key, 'success' => $result]); - return apcu_delete($key); + return $result; } /** @@ -148,6 +204,8 @@ public function clear(): bool APC_ITER_NONE, ); apcu_delete($iterator); + $this->_eventClass = CacheClearedEvent::class; + $this->dispatchEvent(CacheClearedEvent::NAME); return true; } @@ -159,6 +217,9 @@ public function clear(): bool } } + $this->_eventClass = CacheClearedEvent::class; + $this->dispatchEvent(CacheClearedEvent::NAME); + return true; } @@ -175,8 +236,17 @@ public function add(string $key, mixed $value): bool { $key = $this->_key($key); $duration = $this->_config['duration']; + $this->_eventClass = CacheBeforeAddEvent::class; + $this->dispatchEvent(CacheBeforeAddEvent::NAME, ['key' => $key, 'value' => $value]); + + $result = apcu_add($key, $value, $duration); - return apcu_add($key, $value, $duration); + $this->_eventClass = CacheAfterAddEvent::class; + $this->dispatchEvent(CacheAfterAddEvent::NAME, [ + 'key' => $key, 'value' => $value, 'success' => $result, + ]); + + return $result; } /** @@ -234,6 +304,8 @@ public function clearGroup(string $group): bool { $success = false; apcu_inc($this->_config['prefix'] . $group, 1, $success); + $this->_eventClass = CacheGroupClearEvent::class; + $this->dispatchEvent(CacheGroupClearEvent::NAME, ['group' => $group]); return $success; } diff --git a/Engine/ArrayEngine.php b/Engine/ArrayEngine.php index b194e6fdd..8341fbff4 100644 --- a/Engine/ArrayEngine.php +++ b/Engine/ArrayEngine.php @@ -17,6 +17,18 @@ namespace Cake\Cache\Engine; use Cake\Cache\CacheEngine; +use Cake\Cache\Event\CacheAfterDecrementEvent; +use Cake\Cache\Event\CacheAfterDeleteEvent; +use Cake\Cache\Event\CacheAfterGetEvent; +use Cake\Cache\Event\CacheAfterIncrementEvent; +use Cake\Cache\Event\CacheAfterSetEvent; +use Cake\Cache\Event\CacheBeforeDecrementEvent; +use Cake\Cache\Event\CacheBeforeDeleteEvent; +use Cake\Cache\Event\CacheBeforeGetEvent; +use Cake\Cache\Event\CacheBeforeIncrementEvent; +use Cake\Cache\Event\CacheBeforeSetEvent; +use Cake\Cache\Event\CacheClearedEvent; +use Cake\Cache\Event\CacheGroupClearEvent; use DateInterval; /** @@ -54,8 +66,15 @@ public function set(string $key, mixed $value, DateInterval|int|null $ttl = null { $key = $this->_key($key); $expires = time() + $this->duration($ttl); + + $this->_eventClass = CacheBeforeSetEvent::class; + $this->dispatchEvent(CacheBeforeSetEvent::NAME, ['key' => $key, 'value' => $value, 'ttl' => $ttl]); + $this->data[$key] = ['exp' => $expires, 'val' => $value]; + $this->_eventClass = CacheAfterSetEvent::class; + $this->dispatchEvent(CacheAfterSetEvent::NAME, ['key' => $key, 'value' => $value, 'success' => true]); + return true; } @@ -70,7 +89,13 @@ public function set(string $key, mixed $value, DateInterval|int|null $ttl = null public function get(string $key, mixed $default = null): mixed { $key = $this->_key($key); + $this->_eventClass = CacheBeforeGetEvent::class; + $this->dispatchEvent(CacheBeforeGetEvent::NAME, ['key' => $key, 'default' => $default]); + + $this->_eventClass = CacheAfterGetEvent::class; if (!isset($this->data[$key])) { + $this->dispatchEvent(CacheAfterGetEvent::NAME, ['key' => $key, 'value' => null, 'success' => false]); + return $default; } $data = $this->data[$key]; @@ -79,10 +104,13 @@ public function get(string $key, mixed $default = null): mixed $now = time(); if ($data['exp'] <= $now) { unset($this->data[$key]); + $this->dispatchEvent(CacheAfterGetEvent::NAME, ['key' => $key, 'value' => null, 'success' => false]); return $default; } + $this->dispatchEvent(CacheAfterGetEvent::NAME, ['key' => $key, 'value' => $data['val'], 'success' => true]); + return $data['val']; } @@ -99,9 +127,18 @@ public function increment(string $key, int $offset = 1): int|false $this->set($key, 0); } $key = $this->_key($key); + $this->_eventClass = CacheBeforeIncrementEvent::class; + $this->dispatchEvent(CacheBeforeIncrementEvent::NAME, ['key' => $key, 'offset' => $offset]); + $this->data[$key]['val'] += $offset; + $val = $this->data[$key]['val']; - return $this->data[$key]['val']; + $this->_eventClass = CacheAfterIncrementEvent::class; + $this->dispatchEvent('Cache.afterIncrement', [ + 'key' => $key, 'offset' => $offset, 'success' => true, 'value' => $val, + ]); + + return $val; } /** @@ -117,8 +154,16 @@ public function decrement(string $key, int $offset = 1): int|false $this->set($key, 0); } $key = $this->_key($key); + $this->_eventClass = CacheBeforeDecrementEvent::class; + $this->dispatchEvent(CacheBeforeDecrementEvent::NAME, ['key' => $key, 'offset' => $offset]); + $this->data[$key]['val'] -= $offset; + $this->_eventClass = CacheAfterDecrementEvent::class; + $this->dispatchEvent(CacheAfterDecrementEvent::NAME, [ + 'key' => $key, 'offset' => $offset, 'success' => true, 'value' => $this->data[$key]['val'], + ]); + return $this->data[$key]['val']; } @@ -131,8 +176,14 @@ public function decrement(string $key, int $offset = 1): int|false public function delete(string $key): bool { $key = $this->_key($key); + $this->_eventClass = CacheBeforeDeleteEvent::class; + $this->dispatchEvent(CacheBeforeDeleteEvent::NAME, ['key' => $key]); + unset($this->data[$key]); + $this->_eventClass = CacheAfterDeleteEvent::class; + $this->dispatchEvent(CacheAfterDeleteEvent::NAME, ['key' => $key, 'success' => true]); + return true; } @@ -144,6 +195,8 @@ public function delete(string $key): bool public function clear(): bool { $this->data = []; + $this->_eventClass = CacheClearedEvent::class; + $this->dispatchEvent(CacheClearedEvent::NAME); return true; } @@ -181,6 +234,8 @@ public function clearGroup(string $group): bool if (isset($this->data[$key])) { $this->data[$key]['val'] += 1; } + $this->_eventClass = CacheGroupClearEvent::class; + $this->dispatchEvent(CacheGroupClearEvent::NAME, ['group' => $group]); return true; } diff --git a/Engine/FileEngine.php b/Engine/FileEngine.php index a74385bf8..e04ccafe0 100644 --- a/Engine/FileEngine.php +++ b/Engine/FileEngine.php @@ -17,6 +17,14 @@ namespace Cake\Cache\Engine; use Cake\Cache\CacheEngine; +use Cake\Cache\Event\CacheAfterDeleteEvent; +use Cake\Cache\Event\CacheAfterGetEvent; +use Cake\Cache\Event\CacheAfterSetEvent; +use Cake\Cache\Event\CacheBeforeDeleteEvent; +use Cake\Cache\Event\CacheBeforeGetEvent; +use Cake\Cache\Event\CacheBeforeSetEvent; +use Cake\Cache\Event\CacheClearedEvent; +use Cake\Cache\Event\CacheGroupClearEvent; use CallbackFilterIterator; use DateInterval; use Exception; @@ -117,11 +125,19 @@ public function set(string $key, mixed $value, DateInterval|int|null $ttl = null } $key = $this->_key($key); + $this->_eventClass = CacheBeforeSetEvent::class; + $this->dispatchEvent(CacheBeforeSetEvent::NAME, ['key' => $key, 'value' => $value, 'ttl' => $ttl]); + $this->_eventClass = CacheAfterSetEvent::class; if ($this->_setKey($key, true) === false) { + $this->dispatchEvent(CacheAfterSetEvent::NAME, [ + 'key' => $key, 'value' => $value, 'success' => false, + ]); + return false; } + $origValue = $value; if (!empty($this->_config['serialize'])) { $value = serialize($value); } @@ -143,6 +159,10 @@ public function set(string $key, mixed $value, DateInterval|int|null $ttl = null } unset($this->_File); + $this->dispatchEvent(CacheAfterSetEvent::NAME, [ + 'key' => $key, 'value' => $origValue, 'success' => $success, + ]); + return $success; } @@ -157,8 +177,13 @@ public function set(string $key, mixed $value, DateInterval|int|null $ttl = null public function get(string $key, mixed $default = null): mixed { $key = $this->_key($key); + $this->_eventClass = CacheBeforeGetEvent::class; + $this->dispatchEvent(CacheBeforeGetEvent::NAME, ['key' => $key, 'default' => $default]); + $this->_eventClass = CacheAfterGetEvent::class; if (!$this->_init || $this->_setKey($key) === false) { + $this->dispatchEvent(CacheAfterGetEvent::NAME, ['key' => $key, 'value' => null, 'success' => false]); + return $default; } @@ -174,6 +199,7 @@ public function get(string $key, mixed $default = null): mixed if ($this->_config['lock']) { $this->_File->flock(LOCK_UN); } + $this->dispatchEvent(CacheAfterGetEvent::NAME, ['key' => $key, 'value' => null, 'success' => false]); return $default; } @@ -192,9 +218,14 @@ public function get(string $key, mixed $default = null): mixed $data = trim($data); if ($data !== '' && !empty($this->_config['serialize'])) { - return unserialize($data); + $data = unserialize($data); + $this->dispatchEvent(CacheAfterGetEvent::NAME, ['key' => $key, 'value' => $data, 'success' => true]); + + return $data; } + $this->dispatchEvent(CacheAfterGetEvent::NAME, ['key' => $key, 'value' => $data, 'success' => true]); + return $data; } @@ -208,8 +239,13 @@ public function get(string $key, mixed $default = null): mixed public function delete(string $key): bool { $key = $this->_key($key); + $this->_eventClass = CacheBeforeDeleteEvent::class; + $this->dispatchEvent(CacheBeforeDeleteEvent::NAME, ['key' => $key]); + $this->_eventClass = CacheAfterDeleteEvent::class; if ($this->_setKey($key) === false || !$this->_init) { + $this->dispatchEvent(CacheAfterDeleteEvent::NAME, ['key' => $key, 'success' => false]); + return false; } @@ -217,9 +253,13 @@ public function delete(string $key): bool unset($this->_File); if ($path === false) { + $this->dispatchEvent(CacheAfterDeleteEvent::NAME, ['key' => $key, 'success' => false]); + return false; } + $this->dispatchEvent(CacheAfterDeleteEvent::NAME, ['key' => $key, 'success' => true]); + // phpcs:disable return @unlink($path); // phpcs:enable @@ -274,6 +314,8 @@ public function clear(): bool // unsetting iterators helps releasing possible locks in certain environments, // which could otherwise make `rmdir()` fail unset($directory, $iterator); + $this->_eventClass = CacheClearedEvent::class; + $this->dispatchEvent(CacheClearedEvent::NAME); return true; } @@ -483,6 +525,8 @@ function (SplFileInfo $current) use ($group, $prefix) { // unsetting iterators helps releasing possible locks in certain environments, // which could otherwise make `rmdir()` fail unset($directoryIterator, $contents, $filtered); + $this->_eventClass = CacheGroupClearEvent::class; + $this->dispatchEvent(CacheGroupClearEvent::NAME, ['group' => $group]); return true; } diff --git a/Engine/MemcachedEngine.php b/Engine/MemcachedEngine.php index 6a2d19ec1..4f5e8d164 100644 --- a/Engine/MemcachedEngine.php +++ b/Engine/MemcachedEngine.php @@ -17,6 +17,20 @@ namespace Cake\Cache\Engine; use Cake\Cache\CacheEngine; +use Cake\Cache\Event\CacheAfterAddEvent; +use Cake\Cache\Event\CacheAfterDecrementEvent; +use Cake\Cache\Event\CacheAfterDeleteEvent; +use Cake\Cache\Event\CacheAfterGetEvent; +use Cake\Cache\Event\CacheAfterIncrementEvent; +use Cake\Cache\Event\CacheAfterSetEvent; +use Cake\Cache\Event\CacheBeforeAddEvent; +use Cake\Cache\Event\CacheBeforeDecrementEvent; +use Cake\Cache\Event\CacheBeforeDeleteEvent; +use Cake\Cache\Event\CacheBeforeGetEvent; +use Cake\Cache\Event\CacheBeforeIncrementEvent; +use Cake\Cache\Event\CacheBeforeSetEvent; +use Cake\Cache\Event\CacheClearedEvent; +use Cake\Cache\Event\CacheGroupClearEvent; use Cake\Cache\Exception\InvalidArgumentException; use Cake\Core\Exception\CakeException; use DateInterval; @@ -305,9 +319,17 @@ public function getOption(int $name): string|int|bool|null */ public function set(string $key, mixed $value, DateInterval|int|null $ttl = null): bool { + $key = $this->_key($key); $duration = $this->duration($ttl); + $this->_eventClass = CacheBeforeSetEvent::class; + $this->dispatchEvent(CacheBeforeSetEvent::NAME, ['key' => $key, 'value' => $value, 'ttl' => $ttl]); + + $success = $this->_Memcached->set($key, $value, $duration); - return $this->_Memcached->set($this->_key($key), $value, $duration); + $this->_eventClass = CacheAfterSetEvent::class; + $this->dispatchEvent(CacheAfterSetEvent::NAME, ['key' => $key, 'value' => $value, 'success' => $success]); + + return $success; } /** @@ -341,11 +363,20 @@ public function setMultiple(iterable $values, DateInterval|int|null $ttl = null) public function get(string $key, mixed $default = null): mixed { $key = $this->_key($key); + $this->_eventClass = CacheBeforeGetEvent::class; + $this->dispatchEvent(CacheBeforeGetEvent::NAME, ['key' => $key, 'default' => $default]); + $value = $this->_Memcached->get($key); + + $this->_eventClass = CacheAfterGetEvent::class; if ($this->_Memcached->getResultCode() == Memcached::RES_NOTFOUND) { + $this->dispatchEvent(CacheAfterGetEvent::NAME, ['key' => $key, 'value' => null, 'success' => false]); + return $default; } + $this->dispatchEvent(CacheAfterGetEvent::NAME, ['key' => $key, 'value' => $value, 'success' => true]); + return $value; } @@ -386,7 +417,18 @@ public function getMultiple(iterable $keys, mixed $default = null): iterable */ public function increment(string $key, int $offset = 1): int|false { - return $this->_Memcached->increment($this->_key($key), $offset); + $key = $this->_key($key); + $this->_eventClass = CacheBeforeIncrementEvent::class; + $this->dispatchEvent(CacheBeforeIncrementEvent::NAME, ['key' => $key, 'offset' => $offset]); + + $value = $this->_Memcached->increment($key, $offset); + + $this->_eventClass = CacheAfterIncrementEvent::class; + $this->dispatchEvent(CacheAfterIncrementEvent::NAME, [ + 'key' => $key, 'offset' => $offset, 'success' => $value !== false, 'value' => $value, + ]); + + return $value; } /** @@ -398,7 +440,18 @@ public function increment(string $key, int $offset = 1): int|false */ public function decrement(string $key, int $offset = 1): int|false { - return $this->_Memcached->decrement($this->_key($key), $offset); + $key = $this->_key($key); + $this->_eventClass = CacheBeforeDecrementEvent::class; + $this->dispatchEvent(CacheBeforeDecrementEvent::NAME, ['key' => $key, 'offset' => $offset]); + + $value = $this->_Memcached->decrement($key, $offset); + + $this->_eventClass = CacheAfterDecrementEvent::class; + $this->dispatchEvent(CacheAfterDecrementEvent::NAME, [ + 'key' => $key, 'offset' => $offset, 'success' => $value !== false, 'value' => $value, + ]); + + return $value; } /** @@ -410,7 +463,16 @@ public function decrement(string $key, int $offset = 1): int|false */ public function delete(string $key): bool { - return $this->_Memcached->delete($this->_key($key)); + $key = $this->_key($key); + $this->_eventClass = CacheBeforeDeleteEvent::class; + $this->dispatchEvent(CacheBeforeDeleteEvent::NAME, ['key' => $key]); + + $success = $this->_Memcached->delete($key); + + $this->_eventClass = CacheAfterDeleteEvent::class; + $this->dispatchEvent(CacheAfterDeleteEvent::NAME, ['key' => $key, 'success' => $success]); + + return $success; } /** @@ -423,11 +485,18 @@ public function delete(string $key): bool public function deleteMultiple(iterable $keys): bool { $cacheKeys = []; + $this->_eventClass = CacheBeforeDeleteEvent::class; foreach ($keys as $key) { $cacheKeys[] = $this->_key($key); + $this->dispatchEvent(CacheBeforeDeleteEvent::NAME, ['key' => $key]); + } + $success = (bool)$this->_Memcached->deleteMulti($cacheKeys); + $this->_eventClass = CacheAfterDeleteEvent::class; + foreach ($cacheKeys as $key) { + $this->dispatchEvent(CacheAfterDeleteEvent::NAME, ['key' => $key, 'success' => $success]); } - return (bool)$this->_Memcached->deleteMulti($cacheKeys); + return $success; } /** @@ -447,6 +516,8 @@ public function clear(): bool $this->_Memcached->delete($key); } } + $this->_eventClass = CacheClearedEvent::class; + $this->dispatchEvent(CacheClearedEvent::NAME); return true; } @@ -463,7 +534,17 @@ public function add(string $key, mixed $value): bool $duration = $this->_config['duration']; $key = $this->_key($key); - return $this->_Memcached->add($key, $value, $duration); + $this->_eventClass = CacheBeforeAddEvent::class; + $this->dispatchEvent(CacheBeforeAddEvent::NAME, ['key' => $key, 'value' => $value]); + + $success = $this->_Memcached->add($key, $value, $duration); + + $this->_eventClass = CacheAfterAddEvent::class; + $this->dispatchEvent(CacheAfterAddEvent::NAME, [ + 'key' => $key, 'value' => $value, 'success' => $success, + ]); + + return $success; } /** @@ -510,6 +591,10 @@ public function groups(): array */ public function clearGroup(string $group): bool { - return (bool)$this->_Memcached->increment($this->_config['prefix'] . $group); + $result = (bool)$this->_Memcached->increment($this->_config['prefix'] . $group); + $this->_eventClass = CacheGroupClearEvent::class; + $this->dispatchEvent(CacheGroupClearEvent::NAME, ['group' => $group]); + + return $result; } } diff --git a/Engine/RedisEngine.php b/Engine/RedisEngine.php index ee05d655c..80ee3f1fb 100644 --- a/Engine/RedisEngine.php +++ b/Engine/RedisEngine.php @@ -18,6 +18,20 @@ namespace Cake\Cache\Engine; use Cake\Cache\CacheEngine; +use Cake\Cache\Event\CacheAfterAddEvent; +use Cake\Cache\Event\CacheAfterDecrementEvent; +use Cake\Cache\Event\CacheAfterDeleteEvent; +use Cake\Cache\Event\CacheAfterGetEvent; +use Cake\Cache\Event\CacheAfterIncrementEvent; +use Cake\Cache\Event\CacheAfterSetEvent; +use Cake\Cache\Event\CacheBeforeAddEvent; +use Cake\Cache\Event\CacheBeforeDecrementEvent; +use Cake\Cache\Event\CacheBeforeDeleteEvent; +use Cake\Cache\Event\CacheBeforeGetEvent; +use Cake\Cache\Event\CacheBeforeIncrementEvent; +use Cake\Cache\Event\CacheBeforeSetEvent; +use Cake\Cache\Event\CacheClearedEvent; +use Cake\Cache\Event\CacheGroupClearEvent; use Cake\Core\Exception\CakeException; use Cake\Log\Log; use DateInterval; @@ -331,13 +345,26 @@ public function set(string $key, mixed $value, DateInterval|int|null $ttl = null { $key = $this->_key($key); $value = $this->serialize($value); + $this->_eventClass = CacheBeforeSetEvent::class; + $this->dispatchEvent(CacheBeforeSetEvent::NAME, ['key' => $key, 'value' => $value, 'ttl' => $ttl]); + $this->_eventClass = CacheAfterSetEvent::class; $duration = $this->duration($ttl); if ($duration === 0) { - return $this->_Redis->set($key, $value); + $success = $this->_Redis->set($key, $value); + $this->dispatchEvent(CacheAfterSetEvent::NAME, [ + 'key' => $key, 'value' => $value, 'success' => $success, + ]); + + return $success; } - return $this->_Redis->setEx($key, $duration, $value); + $success = $this->_Redis->setEx($key, $duration, $value); + $this->dispatchEvent(CacheAfterSetEvent::NAME, [ + 'key' => $key, 'value' => $value, 'success' => $success, + ]); + + return $success; } /** @@ -350,12 +377,23 @@ public function set(string $key, mixed $value, DateInterval|int|null $ttl = null */ public function get(string $key, mixed $default = null): mixed { - $value = $this->_Redis->get($this->_key($key)); + $key = $this->_key($key); + $this->_eventClass = CacheBeforeGetEvent::class; + $this->dispatchEvent(CacheBeforeGetEvent::NAME, ['key' => $key, 'default' => $default]); + + $value = $this->_Redis->get($key); + + $this->_eventClass = CacheAfterGetEvent::class; if ($value === false) { + $this->dispatchEvent(CacheAfterGetEvent::NAME, ['key' => $key, 'value' => null, 'success' => false]); + return $default; } - return $this->unserialize($value); + $data = $this->unserialize($value); + $this->dispatchEvent(CacheAfterGetEvent::NAME, ['key' => $key, 'value' => $value, 'success' => true]); + + return $data; } /** @@ -380,7 +418,15 @@ public function increment(string $key, int $offset = 1): int|false $duration = $this->_config['duration']; $key = $this->_key($key); + $this->_eventClass = CacheBeforeIncrementEvent::class; + $this->dispatchEvent(CacheBeforeIncrementEvent::NAME, ['key' => $key, 'offset' => $offset]); + $value = $this->_Redis->incrBy($key, $offset); + + $this->_eventClass = CacheAfterIncrementEvent::class; + $this->dispatchEvent(CacheAfterIncrementEvent::NAME, [ + 'key' => $key, 'offset' => $offset, 'success' => $value !== false, 'value' => $value, + ]); if ($duration > 0) { $this->_Redis->expire($key, $duration); } @@ -399,8 +445,15 @@ public function decrement(string $key, int $offset = 1): int|false { $duration = $this->_config['duration']; $key = $this->_key($key); + $this->_eventClass = CacheBeforeDecrementEvent::class; + $this->dispatchEvent(CacheBeforeDecrementEvent::NAME, ['key' => $key, 'offset' => $offset]); $value = $this->_Redis->decrBy($key, $offset); + + $this->_eventClass = CacheAfterDecrementEvent::class; + $this->dispatchEvent(CacheAfterDecrementEvent::NAME, [ + 'key' => $key, 'offset' => $offset, 'success' => $value !== false, 'value' => $value, + ]); if ($duration > 0) { $this->_Redis->expire($key, $duration); } @@ -417,8 +470,15 @@ public function decrement(string $key, int $offset = 1): int|false public function delete(string $key): bool { $key = $this->_key($key); + $this->_eventClass = CacheBeforeDeleteEvent::class; + $this->dispatchEvent(CacheBeforeDeleteEvent::NAME, ['key' => $key]); + + $success = (int)$this->_Redis->del($key) > 0; - return (int)$this->_Redis->del($key) > 0; + $this->_eventClass = CacheAfterDeleteEvent::class; + $this->dispatchEvent(CacheAfterDeleteEvent::NAME, ['key' => $key, 'success' => $success]); + + return $success; } /** @@ -432,8 +492,15 @@ public function delete(string $key): bool public function deleteAsync(string $key): bool { $key = $this->_key($key); + $this->_eventClass = CacheBeforeDeleteEvent::class; + $this->dispatchEvent(CacheBeforeDeleteEvent::NAME, ['key' => $key]); + + $success = (int)$this->_Redis->unlink($key) > 0; - return (int)$this->_Redis->unlink($key) > 0; + $this->_eventClass = CacheAfterDeleteEvent::class; + $this->dispatchEvent(CacheAfterDeleteEvent::NAME, ['key' => $key, 'success' => $success]); + + return $success; } /** @@ -445,6 +512,8 @@ public function clear(): bool { if ($this->getConfig('clearUsesFlushDb')) { $this->flushDB(true); + $this->_eventClass = CacheClearedEvent::class; + $this->dispatchEvent(CacheClearedEvent::NAME); return true; } @@ -456,6 +525,8 @@ public function clear(): bool $isDeleted = ((int)$this->_Redis->unlink($key) > 0); $isAllDeleted = $isAllDeleted && $isDeleted; } + $this->_eventClass = CacheClearedEvent::class; + $this->dispatchEvent(CacheClearedEvent::NAME); return $isAllDeleted; } @@ -469,6 +540,8 @@ public function clearBlocking(): bool { if ($this->getConfig('clearUsesFlushDb')) { $this->flushDB(false); + $this->_eventClass = CacheClearedEvent::class; + $this->dispatchEvent(CacheClearedEvent::NAME); return true; } @@ -481,6 +554,8 @@ public function clearBlocking(): bool $isDeleted = ((int)$this->_Redis->del($key) > 0); $isAllDeleted = $isAllDeleted && $isDeleted; } + $this->_eventClass = CacheClearedEvent::class; + $this->dispatchEvent(CacheClearedEvent::NAME); return $isAllDeleted; } @@ -498,11 +573,23 @@ public function add(string $key, mixed $value): bool { $duration = $this->_config['duration']; $key = $this->_key($key); + $origValue = $value; $value = $this->serialize($value); + $this->_eventClass = CacheBeforeAddEvent::class; + $this->dispatchEvent(CacheBeforeAddEvent::NAME, ['key' => $key, 'value' => $origValue]); + + $this->_eventClass = CacheAfterAddEvent::class; if ($this->_Redis->set($key, $value, ['nx', 'ex' => $duration])) { + $this->dispatchEvent(CacheAfterAddEvent::NAME, [ + 'key' => $key, 'value' => $origValue, 'success' => true, + ]); + return true; } + $this->dispatchEvent(CacheAfterAddEvent::NAME, [ + 'key' => $key, 'value' => $origValue, 'success' => false, + ]); return false; } @@ -538,7 +625,11 @@ public function groups(): array */ public function clearGroup(string $group): bool { - return (bool)$this->_Redis->incr($this->_config['prefix'] . $group); + $success = (bool)$this->_Redis->incr($this->_config['prefix'] . $group); + $this->_eventClass = CacheGroupClearEvent::class; + $this->dispatchEvent(CacheGroupClearEvent::NAME, ['group' => $group]); + + return $success; } /** diff --git a/Event/CacheAfterAddEvent.php b/Event/CacheAfterAddEvent.php new file mode 100644 index 000000000..d0b5fd87c --- /dev/null +++ b/Event/CacheAfterAddEvent.php @@ -0,0 +1,103 @@ + + */ +class CacheAfterAddEvent extends Event +{ + public const NAME = 'Cache.afterAdd'; + + protected string $key; + + protected mixed $value = null; + + /** + * Constructor + * + * @param string $name Name of the event + * @param \Cake\Cache\CacheEngine $subject The Cache engine instance this event applies to. + * @param array $data Any value you wish to be transported with this event to it can be read by listeners. + */ + public function __construct(string $name, CacheEngine $subject, array $data = []) + { + if (isset($data['key'])) { + $this->key = $data['key']; + unset($data['key']); + } + if (isset($data['value'])) { + $this->value = $data['value']; + unset($data['value']); + } + if (isset($data['success'])) { + $this->result = $data['success']; + unset($data['success']); + } + + parent::__construct($name, $subject, $data); + } + + /** + * The result value of the event listeners + * + * @return bool|null + */ + public function getResult(): ?bool + { + return $this->result; + } + + /** + * Listeners can attach a result value to the event. + * + * @param mixed $value The value to set. + * @return $this + */ + public function setResult(mixed $value = null) + { + if ($value !== null && !is_bool($value)) { + throw new InvalidArgumentException( + 'The result for CacheEngine events must be a `bool`.', + ); + } + + return parent::setResult($value); + } + + /** + * @return string + */ + public function getKey(): string + { + return $this->key; + } + + /** + * @return mixed + */ + public function getValue(): mixed + { + return $this->value; + } +} diff --git a/Event/CacheAfterDecrementEvent.php b/Event/CacheAfterDecrementEvent.php new file mode 100644 index 000000000..aaea59faa --- /dev/null +++ b/Event/CacheAfterDecrementEvent.php @@ -0,0 +1,123 @@ + + */ +class CacheAfterDecrementEvent extends Event +{ + public const NAME = 'Cache.afterDecrement'; + + protected string $key; + + protected int $offset; + + protected mixed $value; + + /** + * Constructor + * + * @param string $name Name of the event + * @param \Cake\Cache\CacheEngine $subject The Cache engine instance this event applies to. + * @param array $data Any value you wish to be transported with this event to it can be read by listeners. + */ + public function __construct(string $name, CacheEngine $subject, array $data = []) + { + if (isset($data['key'])) { + $this->key = $data['key']; + unset($data['key']); + } + if (isset($data['offset'])) { + $this->offset = $data['offset']; + unset($data['offset']); + } + if (isset($data['value'])) { + $this->value = $data['value']; + unset($data['value']); + } + if (isset($data['success'])) { + $this->result = $data['success']; + unset($data['success']); + } + + parent::__construct($name, $subject, $data); + } + + /** + * The result value of the event listeners + * + * @return bool|null + */ + public function getResult(): ?bool + { + return $this->result; + } + + /** + * Listeners can attach a result value to the event. + * + * @param mixed $value The value to set. + * @return $this + */ + public function setResult(mixed $value = null) + { + if ($value !== null && !is_bool($value)) { + throw new InvalidArgumentException( + 'The result for CacheEngine events must be a `bool`.', + ); + } + + return parent::setResult($value); + } + + /** + * Get the cache key. + * + * @return string + */ + public function getKey(): string + { + return $this->key; + } + + /** + * Get the decrement offset. + * + * @return int + */ + public function getOffset(): int + { + return $this->offset; + } + + /** + * Get the new value after decrement. + * + * @return mixed + */ + public function getValue(): mixed + { + return $this->value; + } +} diff --git a/Event/CacheAfterDeleteEvent.php b/Event/CacheAfterDeleteEvent.php new file mode 100644 index 000000000..11cb9a2dc --- /dev/null +++ b/Event/CacheAfterDeleteEvent.php @@ -0,0 +1,89 @@ + + */ +class CacheAfterDeleteEvent extends Event +{ + public const NAME = 'Cache.afterDelete'; + + protected string $key; + + /** + * Constructor + * + * @param string $name Name of the event + * @param \Cake\Cache\CacheEngine $subject The Cache engine instance this event applies to. + * @param array $data Any value you wish to be transported with this event to it can be read by listeners. + */ + public function __construct(string $name, CacheEngine $subject, array $data = []) + { + if (isset($data['key'])) { + $this->key = $data['key']; + unset($data['key']); + } + if (isset($data['success'])) { + $this->result = $data['success']; + unset($data['success']); + } + + parent::__construct($name, $subject, $data); + } + + /** + * The result value of the event listeners + * + * @return bool|null + */ + public function getResult(): ?bool + { + return $this->result; + } + + /** + * Listeners can attach a result value to the event. + * + * @param mixed $value The value to set. + * @return $this + */ + public function setResult(mixed $value = null) + { + if ($value !== null && !is_bool($value)) { + throw new InvalidArgumentException( + 'The result for CacheEngine events must be a `bool`.', + ); + } + + return parent::setResult($value); + } + + /** + * @return string + */ + public function getKey(): string + { + return $this->key; + } +} diff --git a/Event/CacheAfterGetEvent.php b/Event/CacheAfterGetEvent.php new file mode 100644 index 000000000..a3860d4b3 --- /dev/null +++ b/Event/CacheAfterGetEvent.php @@ -0,0 +1,103 @@ + + */ +class CacheAfterGetEvent extends Event +{ + public const NAME = 'Cache.afterGet'; + + protected string $key; + + protected mixed $value = null; + + /** + * Constructor + * + * @param string $name Name of the event + * @param \Cake\Cache\CacheEngine $subject The Cache engine instance this event applies to. + * @param array $data Any value you wish to be transported with this event to it can be read by listeners. + */ + public function __construct(string $name, CacheEngine $subject, array $data = []) + { + if (isset($data['key'])) { + $this->key = $data['key']; + unset($data['key']); + } + if (isset($data['value'])) { + $this->value = $data['value']; + unset($data['value']); + } + if (isset($data['success'])) { + $this->result = $data['success']; + unset($data['success']); + } + + parent::__construct($name, $subject, $data); + } + + /** + * The result value of the event listeners + * + * @return bool|null + */ + public function getResult(): ?bool + { + return $this->result; + } + + /** + * Listeners can attach a result value to the event. + * + * @param mixed $value The value to set. + * @return $this + */ + public function setResult(mixed $value = null) + { + if ($value !== null && !is_bool($value)) { + throw new InvalidArgumentException( + 'The result for CacheEngine events must be a `bool`.', + ); + } + + return parent::setResult($value); + } + + /** + * @return string + */ + public function getKey(): string + { + return $this->key; + } + + /** + * @return mixed + */ + public function getValue(): mixed + { + return $this->value; + } +} diff --git a/Event/CacheAfterIncrementEvent.php b/Event/CacheAfterIncrementEvent.php new file mode 100644 index 000000000..47b726064 --- /dev/null +++ b/Event/CacheAfterIncrementEvent.php @@ -0,0 +1,123 @@ + + */ +class CacheAfterIncrementEvent extends Event +{ + public const NAME = 'Cache.afterIncrement'; + + protected string $key; + + protected int $offset; + + protected mixed $value; + + /** + * Constructor + * + * @param string $name Name of the event + * @param \Cake\Cache\CacheEngine $subject The Cache engine instance this event applies to. + * @param array $data Any value you wish to be transported with this event to it can be read by listeners. + */ + public function __construct(string $name, CacheEngine $subject, array $data = []) + { + if (isset($data['key'])) { + $this->key = $data['key']; + unset($data['key']); + } + if (isset($data['offset'])) { + $this->offset = $data['offset']; + unset($data['offset']); + } + if (isset($data['value'])) { + $this->value = $data['value']; + unset($data['value']); + } + if (isset($data['success'])) { + $this->result = $data['success']; + unset($data['success']); + } + + parent::__construct($name, $subject, $data); + } + + /** + * The result value of the event listeners + * + * @return bool|null + */ + public function getResult(): ?bool + { + return $this->result; + } + + /** + * Listeners can attach a result value to the event. + * + * @param mixed $value The value to set. + * @return $this + */ + public function setResult(mixed $value = null) + { + if ($value !== null && !is_bool($value)) { + throw new InvalidArgumentException( + 'The result for CacheEngine events must be a `bool`.', + ); + } + + return parent::setResult($value); + } + + /** + * Get the cache key. + * + * @return string + */ + public function getKey(): string + { + return $this->key; + } + + /** + * Get the increment offset. + * + * @return int + */ + public function getOffset(): int + { + return $this->offset; + } + + /** + * Get the new value after increment. + * + * @return mixed + */ + public function getValue(): mixed + { + return $this->value; + } +} diff --git a/Event/CacheAfterSetEvent.php b/Event/CacheAfterSetEvent.php new file mode 100644 index 000000000..1ef0d67c4 --- /dev/null +++ b/Event/CacheAfterSetEvent.php @@ -0,0 +1,103 @@ + + */ +class CacheAfterSetEvent extends Event +{ + public const NAME = 'Cache.afterSet'; + + protected string $key; + + protected mixed $value = null; + + /** + * Constructor + * + * @param string $name Name of the event + * @param \Cake\Cache\CacheEngine $subject The Cache engine instance this event applies to. + * @param array $data Any value you wish to be transported with this event to it can be read by listeners. + */ + public function __construct(string $name, CacheEngine $subject, array $data = []) + { + if (isset($data['key'])) { + $this->key = $data['key']; + unset($data['key']); + } + if (isset($data['value'])) { + $this->value = $data['value']; + unset($data['value']); + } + if (isset($data['success'])) { + $this->result = $data['success']; + unset($data['success']); + } + + parent::__construct($name, $subject, $data); + } + + /** + * The result value of the event listeners + * + * @return bool|null + */ + public function getResult(): ?bool + { + return $this->result; + } + + /** + * Listeners can attach a result value to the event. + * + * @param mixed $value The value to set. + * @return $this + */ + public function setResult(mixed $value = null) + { + if ($value !== null && !is_bool($value)) { + throw new InvalidArgumentException( + 'The result for CacheEngine events must be a `bool`.', + ); + } + + return parent::setResult($value); + } + + /** + * @return string + */ + public function getKey(): string + { + return $this->key; + } + + /** + * @return mixed + */ + public function getValue(): mixed + { + return $this->value; + } +} diff --git a/Event/CacheBeforeAddEvent.php b/Event/CacheBeforeAddEvent.php new file mode 100644 index 000000000..ec9b465ef --- /dev/null +++ b/Event/CacheBeforeAddEvent.php @@ -0,0 +1,71 @@ + + */ +class CacheBeforeAddEvent extends Event +{ + public const NAME = 'Cache.beforeAdd'; + + protected string $key; + + protected mixed $value = null; + + /** + * Constructor + * + * @param string $name Name of the event + * @param \Cake\Cache\CacheEngine $subject The Cache engine instance this event applies to. + * @param array $data Any value you wish to be transported with this event to it can be read by listeners. + */ + public function __construct(string $name, CacheEngine $subject, array $data = []) + { + if (isset($data['key'])) { + $this->key = $data['key']; + unset($data['key']); + } + if (isset($data['value'])) { + $this->value = $data['value']; + unset($data['value']); + } + + parent::__construct($name, $subject, $data); + } + + /** + * @return string + */ + public function getKey(): string + { + return $this->key; + } + + /** + * @return mixed + */ + public function getValue(): mixed + { + return $this->value; + } +} diff --git a/Event/CacheBeforeDecrementEvent.php b/Event/CacheBeforeDecrementEvent.php new file mode 100644 index 000000000..5e95dc6df --- /dev/null +++ b/Event/CacheBeforeDecrementEvent.php @@ -0,0 +1,75 @@ + + */ +class CacheBeforeDecrementEvent extends Event +{ + public const NAME = 'Cache.beforeDecrement'; + + protected string $key; + + protected int $offset; + + /** + * Constructor + * + * @param string $name Name of the event + * @param \Cake\Cache\CacheEngine $subject The Cache engine instance this event applies to. + * @param array $data Any value you wish to be transported with this event to it can be read by listeners. + */ + public function __construct(string $name, CacheEngine $subject, array $data = []) + { + if (isset($data['key'])) { + $this->key = $data['key']; + unset($data['key']); + } + if (isset($data['offset'])) { + $this->offset = $data['offset']; + unset($data['offset']); + } + + parent::__construct($name, $subject, $data); + } + + /** + * Get the cache key. + * + * @return string + */ + public function getKey(): string + { + return $this->key; + } + + /** + * Get the decrement offset. + * + * @return int + */ + public function getOffset(): int + { + return $this->offset; + } +} diff --git a/Event/CacheBeforeDeleteEvent.php b/Event/CacheBeforeDeleteEvent.php new file mode 100644 index 000000000..7d63f668c --- /dev/null +++ b/Event/CacheBeforeDeleteEvent.php @@ -0,0 +1,57 @@ + + */ +class CacheBeforeDeleteEvent extends Event +{ + public const NAME = 'Cache.beforeDelete'; + + protected string $key; + + /** + * Constructor + * + * @param string $name Name of the event + * @param \Cake\Cache\CacheEngine $subject The Cache engine instance this event applies to. + * @param array $data Any value you wish to be transported with this event to it can be read by listeners. + */ + public function __construct(string $name, CacheEngine $subject, array $data = []) + { + if (isset($data['key'])) { + $this->key = $data['key']; + unset($data['key']); + } + + parent::__construct($name, $subject, $data); + } + + /** + * @return string + */ + public function getKey(): string + { + return $this->key; + } +} diff --git a/Event/CacheBeforeGetEvent.php b/Event/CacheBeforeGetEvent.php new file mode 100644 index 000000000..8c29e21a3 --- /dev/null +++ b/Event/CacheBeforeGetEvent.php @@ -0,0 +1,71 @@ + + */ +class CacheBeforeGetEvent extends Event +{ + public const NAME = 'Cache.beforeGet'; + + protected string $key; + + protected mixed $default = null; + + /** + * Constructor + * + * @param string $name Name of the event + * @param \Cake\Cache\CacheEngine $subject The Cache engine instance this event applies to. + * @param array $data Any value you wish to be transported with this event to it can be read by listeners. + */ + public function __construct(string $name, CacheEngine $subject, array $data = []) + { + if (isset($data['key'])) { + $this->key = $data['key']; + unset($data['key']); + } + if (isset($data['default'])) { + $this->default = $data['default']; + unset($data['default']); + } + + parent::__construct($name, $subject, $data); + } + + /** + * @return string + */ + public function getKey(): string + { + return $this->key; + } + + /** + * @return mixed + */ + public function getDefault(): mixed + { + return $this->default; + } +} diff --git a/Event/CacheBeforeIncrementEvent.php b/Event/CacheBeforeIncrementEvent.php new file mode 100644 index 000000000..b167b1212 --- /dev/null +++ b/Event/CacheBeforeIncrementEvent.php @@ -0,0 +1,75 @@ + + */ +class CacheBeforeIncrementEvent extends Event +{ + public const NAME = 'Cache.beforeIncrement'; + + protected string $key; + + protected int $offset; + + /** + * Constructor + * + * @param string $name Name of the event + * @param \Cake\Cache\CacheEngine $subject The Cache engine instance this event applies to. + * @param array $data Any value you wish to be transported with this event to it can be read by listeners. + */ + public function __construct(string $name, CacheEngine $subject, array $data = []) + { + if (isset($data['key'])) { + $this->key = $data['key']; + unset($data['key']); + } + if (isset($data['offset'])) { + $this->offset = $data['offset']; + unset($data['offset']); + } + + parent::__construct($name, $subject, $data); + } + + /** + * Get the cache key. + * + * @return string + */ + public function getKey(): string + { + return $this->key; + } + + /** + * Get the increment offset. + * + * @return int + */ + public function getOffset(): int + { + return $this->offset; + } +} diff --git a/Event/CacheBeforeSetEvent.php b/Event/CacheBeforeSetEvent.php new file mode 100644 index 000000000..99306f926 --- /dev/null +++ b/Event/CacheBeforeSetEvent.php @@ -0,0 +1,86 @@ + + */ +class CacheBeforeSetEvent extends Event +{ + public const NAME = 'Cache.beforeSet'; + + protected string $key; + + protected mixed $value = null; + + protected DateInterval|int|null $ttl = null; + + /** + * Constructor + * + * @param string $name Name of the event + * @param \Cake\Cache\CacheEngine $subject The Cache engine instance this event applies to. + * @param array $data Any value you wish to be transported with this event to it can be read by listeners. + */ + public function __construct(string $name, CacheEngine $subject, array $data = []) + { + if (isset($data['key'])) { + $this->key = $data['key']; + unset($data['key']); + } + if (isset($data['value'])) { + $this->value = $data['value']; + unset($data['value']); + } + if (isset($data['ttl'])) { + $this->ttl = $data['ttl']; + unset($data['ttl']); + } + + parent::__construct($name, $subject, $data); + } + + /** + * @return string + */ + public function getKey(): string + { + return $this->key; + } + + /** + * @return mixed + */ + public function getValue(): mixed + { + return $this->value; + } + + /** + * @return \DateInterval|int|null + */ + public function getTtl(): DateInterval|int|null + { + return $this->ttl; + } +} diff --git a/Event/CacheClearedEvent.php b/Event/CacheClearedEvent.php new file mode 100644 index 000000000..362a87c42 --- /dev/null +++ b/Event/CacheClearedEvent.php @@ -0,0 +1,29 @@ + + */ +class CacheClearedEvent extends Event +{ + public const NAME = 'Cache.cleared'; +} diff --git a/Event/CacheGroupClearEvent.php b/Event/CacheGroupClearEvent.php new file mode 100644 index 000000000..fcd792269 --- /dev/null +++ b/Event/CacheGroupClearEvent.php @@ -0,0 +1,59 @@ + + */ +class CacheGroupClearEvent extends Event +{ + public const NAME = 'Cache.clearedGroup'; + + protected string $group; + + /** + * Constructor + * + * @param string $name Name of the event + * @param \Cake\Cache\CacheEngine $subject The Cache engine instance this event applies to. + * @param array $data Any value you wish to be transported with this event to it can be read by listeners. + */ + public function __construct(string $name, CacheEngine $subject, array $data = []) + { + if (isset($data['group'])) { + $this->group = $data['group']; + unset($data['group']); + } + + parent::__construct($name, $subject, $data); + } + + /** + * Get the group name + * + * @return string + */ + public function getGroup(): string + { + return $this->group; + } +} diff --git a/composer.json b/composer.json index 5f7b7710d..7f367d89c 100644 --- a/composer.json +++ b/composer.json @@ -24,6 +24,7 @@ "require": { "php": ">=8.2", "cakephp/core": "5.3.*@dev", + "cakephp/event": "5.3.*@dev", "psr/simple-cache": "^2.0 || ^3.0" }, "provide": { From f9bc9151aa8912539524eb7a3c7c60f03abcbd37 Mon Sep 17 00:00:00 2001 From: mscherer Date: Thu, 30 Oct 2025 14:11:55 +0100 Subject: [PATCH 122/127] Fix up PHPStan version range. --- Engine/RedisEngine.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Engine/RedisEngine.php b/Engine/RedisEngine.php index 80ee3f1fb..434ec2c20 100644 --- a/Engine/RedisEngine.php +++ b/Engine/RedisEngine.php @@ -495,7 +495,8 @@ public function deleteAsync(string $key): bool $this->_eventClass = CacheBeforeDeleteEvent::class; $this->dispatchEvent(CacheBeforeDeleteEvent::NAME, ['key' => $key]); - $success = (int)$this->_Redis->unlink($key) > 0; + $result = $this->_Redis->unlink($key); + $success = is_int($result) && $result > 0; $this->_eventClass = CacheAfterDeleteEvent::class; $this->dispatchEvent(CacheAfterDeleteEvent::NAME, ['key' => $key, 'success' => $success]); @@ -522,7 +523,8 @@ public function clear(): bool $pattern = $this->_config['prefix'] . '*'; foreach ($this->scanKeys($pattern) as $key) { - $isDeleted = ((int)$this->_Redis->unlink($key) > 0); + $result = $this->_Redis->unlink($key); + $isDeleted = is_int($result) && $result > 0; $isAllDeleted = $isAllDeleted && $isDeleted; } $this->_eventClass = CacheClearedEvent::class; @@ -690,14 +692,15 @@ private function scanKeys(string $pattern): Generator foreach ($this->_Redis->_masters() as $node) { $iterator = null; while (true) { - // @phpstan-ignore arguments.count, argument.type $keys = $this->_Redis->scan($iterator, $node, $pattern, (int)$this->_config['scanCount']); if ($keys === false) { break; } - foreach ($keys as $key) { - yield $key; + if (is_array($keys)) { + foreach ($keys as $key) { + yield $key; + } } } } From 23883dc4280dd0c2906175bb7af7be436e230029 Mon Sep 17 00:00:00 2001 From: ADmad Date: Sat, 15 Nov 2025 21:16:09 +0530 Subject: [PATCH 123/127] Improve types (#19059) * Improve types * Apply suggestions from code review --------- Co-authored-by: othercorey --- Cache.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cache.php b/Cache.php index 1b01bd65d..ff115e715 100644 --- a/Cache.php +++ b/Cache.php @@ -331,7 +331,7 @@ public static function read(string $key, string $config = 'default'): mixed * Cache::readMany(['my_data_1', 'my_data_2], 'long_term'); * ``` * - * @param iterable $keys An array or Traversable of keys to fetch from the cache + * @param iterable $keys An array or Traversable of keys to fetch from the cache * @param string $config optional name of the configuration to use. Defaults to 'default' * @return iterable An array containing, for each of the given $keys, * the cached data or false if cached data could not be retrieved. @@ -423,7 +423,7 @@ public static function delete(string $key, string $config = 'default'): bool * Cache::deleteMany(['my_data_1', 'my_data_2], 'long_term'); * ``` * - * @param iterable $keys Array or Traversable of cache keys to be deleted + * @param iterable $keys Array or Traversable of cache keys to be deleted * @param string $config name of the configuration to use. Defaults to 'default' * @return bool True on success, false on failure. * @throws \Cake\Cache\Exception\InvalidArgumentException From 87dd7ed3529b0177e0f8d23d805b51d4c0d6a104 Mon Sep 17 00:00:00 2001 From: mscherer Date: Sun, 16 Nov 2025 09:37:38 +0100 Subject: [PATCH 124/127] Fix up more docblock sentences/types. --- CacheEngine.php | 2 +- CacheEngineInterface.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CacheEngine.php b/CacheEngine.php index 22a180fc0..1b76ee03a 100644 --- a/CacheEngine.php +++ b/CacheEngine.php @@ -264,7 +264,7 @@ abstract public function increment(string $key, int $offset = 1): int|false; * * @param string $key Identifier for the data * @param int $offset How much to subtract - * @return int|false New incremented value, false otherwise + * @return int|false New decremented value, false otherwise */ abstract public function decrement(string $key, int $offset = 1): int|false; diff --git a/CacheEngineInterface.php b/CacheEngineInterface.php index d6e190646..9f6f2ce52 100644 --- a/CacheEngineInterface.php +++ b/CacheEngineInterface.php @@ -51,7 +51,7 @@ public function increment(string $key, int $offset = 1): int|false; * * @param string $key Identifier for the data * @param int $offset How much to subtract - * @return int|false New incremented value, false otherwise + * @return int|false New decremented value, false otherwise */ public function decrement(string $key, int $offset = 1): int|false; From b8636f29b4084866a81aefdbaad96f6f0656022c Mon Sep 17 00:00:00 2001 From: Kevin Pfeifer Date: Sun, 23 Nov 2025 10:53:03 +0100 Subject: [PATCH 125/127] add missing ttl to cache events (#19084) --- CacheEngine.php | 11 ++++++++--- Engine/ApcuEngine.php | 10 ++++++---- Engine/ArrayEngine.php | 8 ++++++-- Engine/FileEngine.php | 9 +++++---- Engine/MemcachedEngine.php | 10 ++++++---- Engine/RedisEngine.php | 16 +++++++++------- Event/CacheAfterAddEvent.php | 15 +++++++++++++++ Event/CacheAfterSetEvent.php | 15 +++++++++++++++ Event/CacheBeforeAddEvent.php | 15 +++++++++++++++ 9 files changed, 85 insertions(+), 24 deletions(-) diff --git a/CacheEngine.php b/CacheEngine.php index 670013893..5821638bb 100644 --- a/CacheEngine.php +++ b/CacheEngine.php @@ -305,22 +305,27 @@ public function add(string $key, mixed $value): bool { $cachedValue = $this->get($key); $prefixedKey = $this->_key($key); + $duration = $this->getConfig('duration'); $this->_eventClass = CacheBeforeAddEvent::class; - $this->dispatchEvent(CacheBeforeAddEvent::NAME, ['key' => $prefixedKey, 'value' => $value]); + $this->dispatchEvent(CacheBeforeAddEvent::NAME, [ + 'key' => $prefixedKey, + 'value' => $value, + 'ttl' => $duration, + ]); if ($cachedValue === null) { $success = $this->set($key, $value); $this->_eventClass = CacheAfterAddEvent::class; $this->dispatchEvent(CacheAfterAddEvent::NAME, [ - 'key' => $prefixedKey, 'value' => $value, 'success' => $success, + 'key' => $prefixedKey, 'value' => $value, 'success' => $success, 'ttl' => $duration, ]); return $success; } $this->_eventClass = CacheAfterAddEvent::class; $this->dispatchEvent(CacheAfterAddEvent::NAME, [ - 'key' => $prefixedKey, 'value' => $value, 'success' => false, + 'key' => $prefixedKey, 'value' => $value, 'success' => false, 'ttl' => $duration, ]); return false; diff --git a/Engine/ApcuEngine.php b/Engine/ApcuEngine.php index c55394da2..506b0620e 100644 --- a/Engine/ApcuEngine.php +++ b/Engine/ApcuEngine.php @@ -82,13 +82,13 @@ public function set(string $key, mixed $value, DateInterval|int|null $ttl = null $duration = $this->duration($ttl); $this->_eventClass = CacheBeforeSetEvent::class; - $this->dispatchEvent(CacheBeforeSetEvent::NAME, ['key' => $key, 'value' => $value, 'ttl' => $ttl]); + $this->dispatchEvent(CacheBeforeSetEvent::NAME, ['key' => $key, 'value' => $value, 'ttl' => $duration]); $success = apcu_store($key, $value, $duration); $this->_eventClass = CacheAfterSetEvent::class; $this->dispatchEvent(CacheAfterSetEvent::NAME, [ - 'key' => $key, 'value' => $value, 'success' => $success, + 'key' => $key, 'value' => $value, 'success' => $success, 'ttl' => $duration, ]); return $success; @@ -237,13 +237,15 @@ public function add(string $key, mixed $value): bool $key = $this->_key($key); $duration = $this->_config['duration']; $this->_eventClass = CacheBeforeAddEvent::class; - $this->dispatchEvent(CacheBeforeAddEvent::NAME, ['key' => $key, 'value' => $value]); + $this->dispatchEvent(CacheBeforeAddEvent::NAME, [ + 'key' => $key, 'value' => $value, 'ttl' => $duration, + ]); $result = apcu_add($key, $value, $duration); $this->_eventClass = CacheAfterAddEvent::class; $this->dispatchEvent(CacheAfterAddEvent::NAME, [ - 'key' => $key, 'value' => $value, 'success' => $result, + 'key' => $key, 'value' => $value, 'success' => $result, 'ttl' => $duration, ]); return $result; diff --git a/Engine/ArrayEngine.php b/Engine/ArrayEngine.php index 8341fbff4..094131bde 100644 --- a/Engine/ArrayEngine.php +++ b/Engine/ArrayEngine.php @@ -68,12 +68,16 @@ public function set(string $key, mixed $value, DateInterval|int|null $ttl = null $expires = time() + $this->duration($ttl); $this->_eventClass = CacheBeforeSetEvent::class; - $this->dispatchEvent(CacheBeforeSetEvent::NAME, ['key' => $key, 'value' => $value, 'ttl' => $ttl]); + $this->dispatchEvent(CacheBeforeSetEvent::NAME, [ + 'key' => $key, 'value' => $value, 'ttl' => $this->duration($ttl), + ]); $this->data[$key] = ['exp' => $expires, 'val' => $value]; $this->_eventClass = CacheAfterSetEvent::class; - $this->dispatchEvent(CacheAfterSetEvent::NAME, ['key' => $key, 'value' => $value, 'success' => true]); + $this->dispatchEvent(CacheAfterSetEvent::NAME, [ + 'key' => $key, 'value' => $value, 'success' => true, 'ttl' => $this->duration($ttl), + ]); return true; } diff --git a/Engine/FileEngine.php b/Engine/FileEngine.php index e04ccafe0..1836f9296 100644 --- a/Engine/FileEngine.php +++ b/Engine/FileEngine.php @@ -124,14 +124,15 @@ public function set(string $key, mixed $value, DateInterval|int|null $ttl = null return false; } + $duration = $this->duration($ttl); $key = $this->_key($key); $this->_eventClass = CacheBeforeSetEvent::class; - $this->dispatchEvent(CacheBeforeSetEvent::NAME, ['key' => $key, 'value' => $value, 'ttl' => $ttl]); + $this->dispatchEvent(CacheBeforeSetEvent::NAME, ['key' => $key, 'value' => $value, 'ttl' => $duration]); $this->_eventClass = CacheAfterSetEvent::class; if ($this->_setKey($key, true) === false) { $this->dispatchEvent(CacheAfterSetEvent::NAME, [ - 'key' => $key, 'value' => $value, 'success' => false, + 'key' => $key, 'value' => $value, 'success' => false, 'ttl' => $duration, ]); return false; @@ -142,7 +143,7 @@ public function set(string $key, mixed $value, DateInterval|int|null $ttl = null $value = serialize($value); } - $expires = time() + $this->duration($ttl); + $expires = time() + $duration; $contents = implode('', [$expires, PHP_EOL, $value, PHP_EOL]); if ($this->_config['lock']) { @@ -160,7 +161,7 @@ public function set(string $key, mixed $value, DateInterval|int|null $ttl = null unset($this->_File); $this->dispatchEvent(CacheAfterSetEvent::NAME, [ - 'key' => $key, 'value' => $origValue, 'success' => $success, + 'key' => $key, 'value' => $origValue, 'success' => $success, 'ttl' => $duration, ]); return $success; diff --git a/Engine/MemcachedEngine.php b/Engine/MemcachedEngine.php index 4f5e8d164..be3cd6000 100644 --- a/Engine/MemcachedEngine.php +++ b/Engine/MemcachedEngine.php @@ -322,12 +322,14 @@ public function set(string $key, mixed $value, DateInterval|int|null $ttl = null $key = $this->_key($key); $duration = $this->duration($ttl); $this->_eventClass = CacheBeforeSetEvent::class; - $this->dispatchEvent(CacheBeforeSetEvent::NAME, ['key' => $key, 'value' => $value, 'ttl' => $ttl]); + $this->dispatchEvent(CacheBeforeSetEvent::NAME, ['key' => $key, 'value' => $value, 'ttl' => $duration]); $success = $this->_Memcached->set($key, $value, $duration); $this->_eventClass = CacheAfterSetEvent::class; - $this->dispatchEvent(CacheAfterSetEvent::NAME, ['key' => $key, 'value' => $value, 'success' => $success]); + $this->dispatchEvent(CacheAfterSetEvent::NAME, [ + 'key' => $key, 'value' => $value, 'success' => $success, 'ttl' => $duration, + ]); return $success; } @@ -535,13 +537,13 @@ public function add(string $key, mixed $value): bool $key = $this->_key($key); $this->_eventClass = CacheBeforeAddEvent::class; - $this->dispatchEvent(CacheBeforeAddEvent::NAME, ['key' => $key, 'value' => $value]); + $this->dispatchEvent(CacheBeforeAddEvent::NAME, ['key' => $key, 'value' => $value, 'ttl' => $duration]); $success = $this->_Memcached->add($key, $value, $duration); $this->_eventClass = CacheAfterAddEvent::class; $this->dispatchEvent(CacheAfterAddEvent::NAME, [ - 'key' => $key, 'value' => $value, 'success' => $success, + 'key' => $key, 'value' => $value, 'success' => $success, 'ttl' => $duration, ]); return $success; diff --git a/Engine/RedisEngine.php b/Engine/RedisEngine.php index 434ec2c20..943234a9b 100644 --- a/Engine/RedisEngine.php +++ b/Engine/RedisEngine.php @@ -345,15 +345,15 @@ public function set(string $key, mixed $value, DateInterval|int|null $ttl = null { $key = $this->_key($key); $value = $this->serialize($value); + $duration = $this->duration($ttl); $this->_eventClass = CacheBeforeSetEvent::class; - $this->dispatchEvent(CacheBeforeSetEvent::NAME, ['key' => $key, 'value' => $value, 'ttl' => $ttl]); + $this->dispatchEvent(CacheBeforeSetEvent::NAME, ['key' => $key, 'value' => $value, 'ttl' => $duration]); $this->_eventClass = CacheAfterSetEvent::class; - $duration = $this->duration($ttl); if ($duration === 0) { $success = $this->_Redis->set($key, $value); $this->dispatchEvent(CacheAfterSetEvent::NAME, [ - 'key' => $key, 'value' => $value, 'success' => $success, + 'key' => $key, 'value' => $value, 'success' => $success, 'ttl' => $duration, ]); return $success; @@ -361,7 +361,7 @@ public function set(string $key, mixed $value, DateInterval|int|null $ttl = null $success = $this->_Redis->setEx($key, $duration, $value); $this->dispatchEvent(CacheAfterSetEvent::NAME, [ - 'key' => $key, 'value' => $value, 'success' => $success, + 'key' => $key, 'value' => $value, 'success' => $success, 'ttl' => $duration, ]); return $success; @@ -579,18 +579,20 @@ public function add(string $key, mixed $value): bool $value = $this->serialize($value); $this->_eventClass = CacheBeforeAddEvent::class; - $this->dispatchEvent(CacheBeforeAddEvent::NAME, ['key' => $key, 'value' => $origValue]); + $this->dispatchEvent(CacheBeforeAddEvent::NAME, [ + 'key' => $key, 'value' => $origValue, 'ttl' => $duration, + ]); $this->_eventClass = CacheAfterAddEvent::class; if ($this->_Redis->set($key, $value, ['nx', 'ex' => $duration])) { $this->dispatchEvent(CacheAfterAddEvent::NAME, [ - 'key' => $key, 'value' => $origValue, 'success' => true, + 'key' => $key, 'value' => $origValue, 'success' => true, 'ttl' => $duration, ]); return true; } $this->dispatchEvent(CacheAfterAddEvent::NAME, [ - 'key' => $key, 'value' => $origValue, 'success' => false, + 'key' => $key, 'value' => $origValue, 'success' => false, 'ttl' => $duration, ]); return false; diff --git a/Event/CacheAfterAddEvent.php b/Event/CacheAfterAddEvent.php index d0b5fd87c..768709483 100644 --- a/Event/CacheAfterAddEvent.php +++ b/Event/CacheAfterAddEvent.php @@ -19,6 +19,7 @@ use Cake\Cache\CacheEngine; use Cake\Cache\Exception\InvalidArgumentException; use Cake\Event\Event; +use DateInterval; /** * Class Cache AfterAdd Event @@ -33,6 +34,8 @@ class CacheAfterAddEvent extends Event protected mixed $value = null; + protected DateInterval|int|null $ttl = null; + /** * Constructor * @@ -54,6 +57,10 @@ public function __construct(string $name, CacheEngine $subject, array $data = [] $this->result = $data['success']; unset($data['success']); } + if (isset($data['ttl'])) { + $this->ttl = $data['ttl']; + unset($data['ttl']); + } parent::__construct($name, $subject, $data); } @@ -100,4 +107,12 @@ public function getValue(): mixed { return $this->value; } + + /** + * @return \DateInterval|int|null + */ + public function getTtl(): DateInterval|int|null + { + return $this->ttl; + } } diff --git a/Event/CacheAfterSetEvent.php b/Event/CacheAfterSetEvent.php index 1ef0d67c4..950dda4d4 100644 --- a/Event/CacheAfterSetEvent.php +++ b/Event/CacheAfterSetEvent.php @@ -19,6 +19,7 @@ use Cake\Cache\CacheEngine; use Cake\Cache\Exception\InvalidArgumentException; use Cake\Event\Event; +use DateInterval; /** * Class Cache AfterSet Event @@ -33,6 +34,8 @@ class CacheAfterSetEvent extends Event protected mixed $value = null; + protected DateInterval|int|null $ttl = null; + /** * Constructor * @@ -54,6 +57,10 @@ public function __construct(string $name, CacheEngine $subject, array $data = [] $this->result = $data['success']; unset($data['success']); } + if (isset($data['ttl'])) { + $this->ttl = $data['ttl']; + unset($data['ttl']); + } parent::__construct($name, $subject, $data); } @@ -100,4 +107,12 @@ public function getValue(): mixed { return $this->value; } + + /** + * @return \DateInterval|int|null + */ + public function getTtl(): DateInterval|int|null + { + return $this->ttl; + } } diff --git a/Event/CacheBeforeAddEvent.php b/Event/CacheBeforeAddEvent.php index ec9b465ef..bb7efe71a 100644 --- a/Event/CacheBeforeAddEvent.php +++ b/Event/CacheBeforeAddEvent.php @@ -18,6 +18,7 @@ use Cake\Cache\CacheEngine; use Cake\Event\Event; +use DateInterval; /** * Class Cache BeforeAdd Event @@ -32,6 +33,8 @@ class CacheBeforeAddEvent extends Event protected mixed $value = null; + protected DateInterval|int|null $ttl = null; + /** * Constructor * @@ -49,6 +52,10 @@ public function __construct(string $name, CacheEngine $subject, array $data = [] $this->value = $data['value']; unset($data['value']); } + if (isset($data['ttl'])) { + $this->ttl = $data['ttl']; + unset($data['ttl']); + } parent::__construct($name, $subject, $data); } @@ -68,4 +75,12 @@ public function getValue(): mixed { return $this->value; } + + /** + * @return \DateInterval|int|null + */ + public function getTtl(): DateInterval|int|null + { + return $this->ttl; + } } From 5dfc549aab56c851d4da692f90f316595bb73a81 Mon Sep 17 00:00:00 2001 From: ADmad Date: Sun, 14 Dec 2025 21:31:41 +0530 Subject: [PATCH 126/127] Fix template annotations (#19118) * Fix template annotations * Add inline @phpstan-ignore for defensive code patterns Replace baseline entries with inline ignores for: - isset.property checks on resources in destructors - method_exists() checks for patch method on EntityInterface - is_callable() checks after method_exists() - SASL support detection in MemcachedEngine Also removes incorrect @var annotations that were less specific than PHPStan's inferred types. * Fix flaky test due to Date header timing * Improve template type inference for Collection classes - Add @param iterable to Collection and iterator constructors This enables PHPStan to infer template types from constructor arguments - Replace ZipIterator baseline entry with inline @phpstan-ignore Keeps the baseline cleaner while still suppressing expected errors * Fix PHPStan errors from typed constructor param Add inline ignores for cases where array types don't match template parameters: - Collection::__unserialize() passes plain array - SortIterator passes sorted array with transformed keys - CollectionTrait::transpose() calls count(current()) on TValue * Remove baseline entry now handled by inline ignore * Revert template annotations on type-transforming iterators ExtractIterator, ReplaceIterator, and ZipIterator transform their output types, so propagating TValue from input to output is incorrect and causes PHPStan false positives. * Revert NestIterator template annotation Children extracted via nestKey can be a different type than parent items, so the type-preserving annotation is incorrect. * Add template annotations to type-transforming iterators - ExtractIterator, ReplaceIterator: Use since keys are preserved but values are transformed - ZipIterator: Use since both keys and values change - NestIterator: Add @extends Collection --------- Co-authored-by: mscherer --- CacheEngine.php | 2 ++ Engine/MemcachedEngine.php | 1 + 2 files changed, 3 insertions(+) diff --git a/CacheEngine.php b/CacheEngine.php index 5821638bb..b634d3f94 100644 --- a/CacheEngine.php +++ b/CacheEngine.php @@ -29,6 +29,8 @@ /** * Storage engine for CakePHP caching + * + * @implements \Cake\Event\EventDispatcherInterface<\Cake\Cache\CacheEngine> */ abstract class CacheEngine implements CacheInterface, CacheEngineInterface, EventDispatcherInterface { diff --git a/Engine/MemcachedEngine.php b/Engine/MemcachedEngine.php index be3cd6000..edcbd88c5 100644 --- a/Engine/MemcachedEngine.php +++ b/Engine/MemcachedEngine.php @@ -199,6 +199,7 @@ public function init(array $config = []): bool } if ($this->_config['username'] !== null && $this->_config['password'] !== null) { + // @phpstan-ignore function.alreadyNarrowedType (check kept for SASL support detection) if (!method_exists($this->_Memcached, 'setSaslAuthData')) { throw new InvalidArgumentException( 'Memcached extension is not built with SASL support', From 22f1e2a2bb54fdbcecdcdc4afae6283157d08e6d Mon Sep 17 00:00:00 2001 From: ADmad Date: Mon, 22 Dec 2025 10:59:31 +0530 Subject: [PATCH 127/127] Improve type inference (#19145) --- CacheEngine.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CacheEngine.php b/CacheEngine.php index b634d3f94..da15733c7 100644 --- a/CacheEngine.php +++ b/CacheEngine.php @@ -30,12 +30,13 @@ /** * Storage engine for CakePHP caching * - * @implements \Cake\Event\EventDispatcherInterface<\Cake\Cache\CacheEngine> + * @template TSubject of \Cake\Cache\CacheEngine + * @implements \Cake\Event\EventDispatcherInterface */ abstract class CacheEngine implements CacheInterface, CacheEngineInterface, EventDispatcherInterface { /** - * @use \Cake\Event\EventDispatcherTrait<\Cake\Cache\CacheEngine> + * @use \Cake\Event\EventDispatcherTrait */ use EventDispatcherTrait; use InstanceConfigTrait;