diff --git a/src/Discord/Discord.php b/src/Discord/Discord.php index edaf07f04..90efe5eb2 100644 --- a/src/Discord/Discord.php +++ b/src/Discord/Discord.php @@ -369,7 +369,9 @@ public function __construct(array $options = []) $this->logger->debug('Initializing DiscordPHP '.self::VERSION.' (DiscordPHP-Http: '.Http::VERSION.' & Gateway: v'.self::GATEWAY_VERSION.') on PHP '.PHP_VERSION); $this->cacheConfig = $options['cache']; - $this->logger->warning('Attached experimental CacheInterface: '.get_class($this->getCacheConfig()->interface)); + if ($cacheConfig = $this->getCacheConfig()) { + $this->logger->warning('Attached experimental CacheInterface: '.get_class($cacheConfig->interface)); + } $connector = new SocketConnector($options['socket_options'], $this->loop); $this->wsFactory = new Connector($this->loop, $connector); @@ -1579,11 +1581,11 @@ public function getHttp(): Http * * @param string $name Repository class name. * - * @return CacheConfig + * @return ?CacheConfig */ public function getCacheConfig($repository_class = AbstractRepository::class) { - if (! isset($this->cacheConfig[$repository_class])) { + if (! array_key_exists($repository_class, $this->cacheConfig)) { $repository_class = AbstractRepository::class; } diff --git a/src/Discord/Helpers/CacheWrapper.php b/src/Discord/Helpers/CacheWrapper.php index 82a6e90ab..1d80ae4e2 100644 --- a/src/Discord/Helpers/CacheWrapper.php +++ b/src/Discord/Helpers/CacheWrapper.php @@ -29,8 +29,7 @@ * * @since 10.0.0 * - * @property-read \React\Cache\CacheInterface|\Psr\SimpleCache\CacheInterface $interface The actual ReactPHP PSR-16 CacheInterface. - * @property-read CacheConfig $config Cache configuration. + * @property-read CacheConfig $config Cache configuration. */ class CacheWrapper { @@ -506,8 +505,8 @@ public function sweep(): int public function __get(string $name) { - if (in_array($name, ['interface', 'config'])) { - return $this->$name; + if ($name === 'config') { + return $this->config; } } } diff --git a/src/Discord/Helpers/LegacyCacheWrapper.php b/src/Discord/Helpers/LegacyCacheWrapper.php new file mode 100644 index 000000000..375c14282 --- /dev/null +++ b/src/Discord/Helpers/LegacyCacheWrapper.php @@ -0,0 +1,207 @@ + + * + * This file is subject to the MIT license that is bundled + * with this source code in the LICENSE.md file. + */ + +namespace Discord\Helpers; + +use Discord\Discord; +use Discord\Parts\Part; +use React\Promise\PromiseInterface; + +use function React\Promise\resolve; + +/** + * Legacy v7.x in memory cache behavior + * + * @since 10.0.0 + * @internal + */ +final class LegacyCacheWrapper extends CacheWrapper +{ + /** + * Repository items array reference. + * + * @var ?Part[] Cache Key => Cache Part. + */ + protected $items; + + /** + * @param Discord $discord + * @param array &$items Repository items passed by reference. + * @param string &$class Part class name. + * + * @internal + */ + public function __construct(Discord $discord, &$items, string &$class) + { + $this->discord = $discord; + $this->items = &$items; + $this->class = &$class; + + $this->prefix = ''; + } + + public function __destruct() + { + } + + /** + * Get Part from cache. + * + * @param string $key + * @param mixed $default + * + * @return PromiseInterface + */ + public function get($key, $default = null) + { + return resolve($this->items[$key] ?? $default); + } + + /** + * Set Part into cache. + * + * @param string $key + * @param Part $value + * + * @return PromiseInterface + */ + public function set($key, $value, $ttl = null) + { + $this->items[$key] = $value; + + return resolve(true); + } + + /** + * Delete Part from cache. + * + * @param string $key + * + * @return PromiseInterface + */ + public function delete($key) + { + if (!array_key_exists($key, $this->items)) { + return resolve(false); + } + + unset($this->items[$key]); + + return resolve(true); + } + + /** + * Get multiple Parts from cache. + * + * @param array $keys + * @param ?Part $default + * + * @return PromiseInterface + */ + public function getMultiple(array $keys, $default = null) + { + $items = []; + foreach ($keys as $key) { + $items[$key] = $this->items[$key] ?? $default; + } + + return resolve($items); + } + + /** + * Set multiple Parts into cache. + * + * @param Part[] $values + * + * @return PromiseInterface + */ + public function setMultiple(array $values, $ttl = null) + { + foreach ($values as $key => $value) { + $this->items[$key] = $value; + } + + return resolve(true); + } + + /** + * Delete multiple Parts from cache. + * + * @param array $keys + * + * @return PromiseInterface + */ + public function deleteMultiple(array $keys) + { + foreach ($keys as $key) { + unset($this->items[$key]); + } + + return resolve(true); + } + + /** + * Clear all Parts from cache. + * + * @return PromiseInterface + */ + public function clear() + { + $this->items = []; + + return resolve(true); + } + + /** + * Check if Part is present in cache. + * + * @param string $key + * + * @return PromiseInterface + */ + public function has($key) + { + return resolve(array_key_exists($key, $this->items)); + } + + /** + * @param Part $part + * + * @return object + */ + public function serializer($part) + { + return (object) (get_object_vars($part) + ['attributes' => $part->getRawAttributes()]); + } + + /** + * @param object $value + * + * @return ?Part + */ + public function unserializer($value) + { + if (empty($value->attributes)) { + $this->discord->getLogger()->warning('Cached Part::$attributes is empty', ['class' => $this->class, 'interface' => 'LEGACY', 'data' => $value]); + } + if (empty($value->created)) { + $this->discord->getLogger()->warning('Cached Part::$created is empty', ['class' => $this->class, 'interface' => 'LEGACY', 'data' => $value]); + } + $part = $this->discord->getFactory()->part($this->class, $value->attributes, $value->created); + foreach ($value as $name => $var) { + if (!in_array($name, ['created', 'attributes'])) { + $part->{$name} = $var; + } + } + + return $part; + } +} \ No newline at end of file diff --git a/src/Discord/Repository/AbstractRepository.php b/src/Discord/Repository/AbstractRepository.php index a6d8be8ce..7ebb58ddc 100755 --- a/src/Discord/Repository/AbstractRepository.php +++ b/src/Discord/Repository/AbstractRepository.php @@ -15,6 +15,7 @@ use Discord\Factory\Factory; use Discord\Helpers\CacheWrapper; use Discord\Helpers\Collection; +use Discord\Helpers\LegacyCacheWrapper; use Discord\Http\Endpoint; use Discord\Http\Http; use Discord\Parts\Part; @@ -90,7 +91,11 @@ public function __construct(Discord $discord, array $vars = []) $this->http = $discord->getHttpClient(); $this->factory = $discord->getFactory(); $this->vars = $vars; - $this->cache = new CacheWrapper($discord, $discord->getCacheConfig(static::class), $this->items, $this->class, $this->vars); + if ($cacheConfig = $discord->getCacheConfig(static::class)) { + $this->cache = new CacheWrapper($discord, $cacheConfig, $this->items, $this->class, $this->vars); + } else { + $this->cache = new LegacyCacheWrapper($discord, $this->items, $this->class); + } parent::__construct([], $this->discrim, $this->class); } @@ -124,7 +129,7 @@ public function freshen(array $queryparams = []): ExtendedPromiseInterface } elseif (! ($this->items[$offset] instanceof WeakReference)) { $this->items[$offset] = WeakReference::create($value); } - $this->cache->interface->delete($this->cache->getPrefix().$offset); + $this->cache->delete($offset); } return $this->cacheFreshen($response); @@ -412,7 +417,7 @@ public function set($offset, $value) return; } - $this->cache->interface->set($this->cache->getPrefix().$offset, $this->cache->serializer($value), $this->cache->config->ttl); + $this->cache->set($offset, $value, $this->cache->config->ttl); $this->items[$offset] = $value; } @@ -431,7 +436,7 @@ public function pull($key, $default = null) if ($item = $this->offsetGet($key)) { $default = $item; unset($this->items[$key]); - $this->cache->interface->delete($this->cache->getPrefix().$key); + $this->cache->delete($key); } return $default; @@ -466,7 +471,7 @@ public function pushItem($item): self if (is_a($item, $this->class)) { $key = $item->{$this->discrim}; $this->items[$key] = $item; - $this->cache->interface->set($this->cache->getPrefix().$key, $this->cache->serializer($item), $this->cache->config->ttl); + $this->cache->set($key, $item); } return $this;