From 194b66faa7ccaceff010e64db4daadec7a27ef99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Fri, 25 Jan 2019 14:12:25 +0800 Subject: [PATCH] Added Model Cacheable. --- composer.json | 1 + src/db-connection/composer.json | 1 + src/db-connection/src/Cache/Cacheable.php | 30 ++++ src/db-connection/src/Cache/Config.php | 102 ++++++++++++ .../src/Cache/Exception/CacheException.php | 17 ++ .../src/Cache/Handler/HandlerInterface.php | 21 +++ .../src/Cache/Handler/RedisHandler.php | 149 ++++++++++++++++++ src/db-connection/src/Cache/Manager.php | 102 ++++++++++++ .../src/Cache/Redis/HashsGetMultiple.php | 49 ++++++ .../src/Cache/Redis/OperatorInterface.php | 20 +++ src/db-connection/src/Model/Model.php | 2 +- 11 files changed, 493 insertions(+), 1 deletion(-) create mode 100644 src/db-connection/src/Cache/Cacheable.php create mode 100644 src/db-connection/src/Cache/Config.php create mode 100644 src/db-connection/src/Cache/Exception/CacheException.php create mode 100644 src/db-connection/src/Cache/Handler/HandlerInterface.php create mode 100644 src/db-connection/src/Cache/Handler/RedisHandler.php create mode 100644 src/db-connection/src/Cache/Manager.php create mode 100644 src/db-connection/src/Cache/Redis/HashsGetMultiple.php create mode 100644 src/db-connection/src/Cache/Redis/OperatorInterface.php diff --git a/composer.json b/composer.json index 65a395da8..a73b0ae48 100644 --- a/composer.json +++ b/composer.json @@ -16,6 +16,7 @@ "psr/http-message": "^1.0.1", "psr/http-server-middleware": "^1.0", "psr/event-dispatcher": "^0.7", + "psr/simple-cache": "^1.0", "fig/http-message-util": "^1.1.2", "nikic/fast-route": "^1.3", "nikic/php-parser": "^4.1", diff --git a/src/db-connection/composer.json b/src/db-connection/composer.json index 2c39bb496..e93bf42b9 100644 --- a/src/db-connection/composer.json +++ b/src/db-connection/composer.json @@ -12,6 +12,7 @@ }, "require": { "php": ">=7.2", + "psr/simple-cache": "^1.0", "hyperf/database": "dev-master", "hyperf/di": "dev-master", "hyperf/event": "dev-master", diff --git a/src/db-connection/src/Cache/Cacheable.php b/src/db-connection/src/Cache/Cacheable.php new file mode 100644 index 000000000..e49645b10 --- /dev/null +++ b/src/db-connection/src/Cache/Cacheable.php @@ -0,0 +1,30 @@ +get(Manager::class); + + return $manager->findFromCache($id, static::class); + } + + public static function findManyFromCache($ids) + { + } +} diff --git a/src/db-connection/src/Cache/Config.php b/src/db-connection/src/Cache/Config.php new file mode 100644 index 000000000..7c9d99895 --- /dev/null +++ b/src/db-connection/src/Cache/Config.php @@ -0,0 +1,102 @@ +cacheKey = $values['cache_key']; + } + if (isset($values['prefix'])) { + $this->prefix = $values['prefix']; + } else { + $this->prefix = $name; + } + if (isset($values['ttl'])) { + $this->ttl = $values['ttl']; + } + if (isset($values['load_script'])) { + $this->loadScript = $values['load_script']; + } + } + + public function getCacheKey(): string + { + return $this->cacheKey; + } + + public function setCacheKey(string $cacheKey): Config + { + $this->cacheKey = $cacheKey; + return $this; + } + + public function getPrefix(): string + { + return $this->prefix; + } + + public function setPrefix(string $prefix): Config + { + $this->prefix = $prefix; + return $this; + } + + public function getTtl(): int + { + return $this->ttl; + } + + public function setTtl(int $ttl): Config + { + $this->ttl = $ttl; + return $this; + } + + public function isLoadScript(): bool + { + return $this->loadScript; + } + + public function setLoadScript(bool $loadScript): Config + { + $this->loadScript = $loadScript; + return $this; + } +} diff --git a/src/db-connection/src/Cache/Exception/CacheException.php b/src/db-connection/src/Cache/Exception/CacheException.php new file mode 100644 index 000000000..79a600026 --- /dev/null +++ b/src/db-connection/src/Cache/Exception/CacheException.php @@ -0,0 +1,17 @@ + 'DEFAULT']; + + public function __construct(ContainerInterface $container, Config $config) + { + $this->container = $container; + if (! $container->has(Redis::class)) { + throw new CacheException(sprintf('Entry[%s] of the container is not exist.', Redis::class)); + } + + $this->redis = $container->get(Redis::class); + $this->config = $config; + $this->multiple = new HashsGetMultiple(); + } + + public function get($key, $default = null) + { + $data = $this->redis->hGetAll($key); + if (! $data) { + return $default; + } + + if ($data == $this->defaultHash) { + return $default; + } + + return $data; + } + + public function set($key, $value, $ttl = null) + { + if (is_array($value)) { + $data = $value; + } elseif ($value instanceof Arrayable) { + $data = $value->toArray(); + } else { + throw new CacheException(sprintf('The value must is array.')); + } + + $data = array_merge($data, $this->defaultHash); + $res = $this->redis->hMSet($key, $data); + if ($ttl && $ttl > 0) { + $this->redis->expire($key, $ttl); + } + + return $res; + } + + public function delete($key) + { + return $this->redis->delete($key); + } + + public function clear() + { + throw new CacheException('Method clear is forbidden.'); + } + + public function getMultiple($keys, $default = null) + { + if ($this->config->isLoadScript()) { + $sha = $this->getLuaSha(); + } + + if (! empty($sha)) { + $list = $this->redis->evalSha($sha, $keys, count($keys)); + } else { + $script = $this->multiple->getScript(); + $list = $this->redis->eval($script, $keys, count($keys)); + } + + return $list; + } + + public function setMultiple($values, $ttl = null) + { + // TODO: Implement setMultiple() method. + } + + public function deleteMultiple($keys) + { + // TODO: Implement deleteMultiple() method. + } + + public function has($key) + { + // TODO: Implement has() method. + } + + public function getConfig(): Config + { + return $this->config; + } + + protected function getLuaSha() + { + if (! empty($this->luaSha)) { + return $this->luaSha; + } + + $sha = $this->redis->script('load', $this->multiple->getScript()); + + return $this->luaSha = $sha; + } +} diff --git a/src/db-connection/src/Cache/Manager.php b/src/db-connection/src/Cache/Manager.php new file mode 100644 index 000000000..0f818c045 --- /dev/null +++ b/src/db-connection/src/Cache/Manager.php @@ -0,0 +1,102 @@ +container = $container; + $this->logger = $container->get(StdoutLoggerInterface::class); + $config = $container->get(ConfigInterface::class); + if (! $config->has('databases')) { + throw new \InvalidArgumentException('config databases is not exist!'); + } + + foreach ($config->get('databases') as $key => $item) { + $handler = $item['handler'] ?? RedisHandler::class; + $config = new Config($item['cache'] ?? [], $key); + $this->handlers[$key] = new $handler($this->container, $config); + } + } + + public function findFromCache($id, string $class) + { + /** @var Model $instance */ + $instance = new $class(); + + $name = $instance->getConnectionName(); + $primaryKey = $instance->getKeyName(); + + if ($handler = $this->handlers[$name] ?? null) { + $key = $this->getCacheKey($id, $instance, $handler->getConfig()); + $data = $handler->get($key); + if ($data) { + return $instance->newFromBuilder($data); + } + + if (is_null($data)) { + $model = $instance->newQuery()->where($primaryKey, '=', $id)->first(); + if ($model) { + $handler->set($key, $model->toArray()); + } else { + $handler->set($key, []); + } + return $model; + } + + return null; + } + + $this->logger->warning('Cache handler not exist, fetch data from database.'); + return $instance->newQuery()->where($primaryKey, '=', $id)->first(); + } + + public function findManyFromCache(array $ids, string $class) + { + } + + protected function getCacheKey($id, Model $model, Config $config) + { + // mc:$prefix:m:$model:$pk:$id + return sprintf( + $config->getCacheKey(), + $config->getPrefix(), + $model->getTable(), + $model->getKeyName(), + $id + ); + } +} diff --git a/src/db-connection/src/Cache/Redis/HashsGetMultiple.php b/src/db-connection/src/Cache/Redis/HashsGetMultiple.php new file mode 100644 index 000000000..410d089b4 --- /dev/null +++ b/src/db-connection/src/Cache/Redis/HashsGetMultiple.php @@ -0,0 +1,49 @@ +