PageRenderTime 27ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/concrete/vendor/zendframework/zend-cache/src/Storage/Adapter/Redis.php

https://gitlab.com/koodersmiikka/operaatio-terveys
PHP | 435 lines | 238 code | 44 blank | 153 comment | 15 complexity | 782b3e6b4f5d6a56d88acf1f78960ec9 MD5 | raw file
  1. <?php
  2. /**
  3. * Zend Framework (http://framework.zend.com/)
  4. *
  5. * @link http://github.com/zendframework/zf2 for the canonical source repository
  6. * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com)
  7. * @license http://framework.zend.com/license/new-bsd New BSD License
  8. */
  9. namespace Zend\Cache\Storage\Adapter;
  10. use Redis as RedisResource;
  11. use RedisException as RedisResourceException;
  12. use stdClass;
  13. use Zend\Cache\Exception;
  14. use Zend\Cache\Storage\Capabilities;
  15. use Zend\Cache\Storage\FlushableInterface;
  16. use Zend\Cache\Storage\TotalSpaceCapableInterface;
  17. class Redis extends AbstractAdapter implements
  18. FlushableInterface,
  19. TotalSpaceCapableInterface
  20. {
  21. /**
  22. * Has this instance be initialized
  23. *
  24. * @var bool
  25. */
  26. protected $initialized = false;
  27. /**
  28. * The redis resource manager
  29. *
  30. * @var null|RedisResourceManager
  31. */
  32. protected $resourceManager;
  33. /**
  34. * The redis resource id
  35. *
  36. * @var null|string
  37. */
  38. protected $resourceId;
  39. /**
  40. * The namespace prefix
  41. *
  42. * @var string
  43. */
  44. protected $namespacePrefix = '';
  45. /**
  46. * Create new Adapter for redis storage
  47. *
  48. * @param null|array|Traversable|RedisOptions $options
  49. * @see \Zend\Cache\Storage\Adapter\Abstract
  50. */
  51. public function __construct($options = null)
  52. {
  53. if (!extension_loaded('redis')) {
  54. throw new Exception\ExtensionNotLoadedException("Redis extension is not loaded");
  55. }
  56. parent::__construct($options);
  57. // reset initialized flag on update option(s)
  58. $initialized = & $this->initialized;
  59. $this->getEventManager()->attach('option', function ($event) use (& $initialized) {
  60. $initialized = false;
  61. });
  62. }
  63. /**
  64. * Get Redis resource
  65. *
  66. * @return RedisResource
  67. */
  68. protected function getRedisResource()
  69. {
  70. if (!$this->initialized) {
  71. $options = $this->getOptions();
  72. // get resource manager and resource id
  73. $this->resourceManager = $options->getResourceManager();
  74. $this->resourceId = $options->getResourceId();
  75. // init namespace prefix
  76. $namespace = $options->getNamespace();
  77. if ($namespace !== '') {
  78. $this->namespacePrefix = $namespace . $options->getNamespaceSeparator();
  79. } else {
  80. $this->namespacePrefix = '';
  81. }
  82. // update initialized flag
  83. $this->initialized = true;
  84. }
  85. return $this->resourceManager->getResource($this->resourceId);
  86. }
  87. /* options */
  88. /**
  89. * Set options.
  90. *
  91. * @param array|Traversable|RedisOptions $options
  92. * @return Redis
  93. * @see getOptions()
  94. */
  95. public function setOptions($options)
  96. {
  97. if (!$options instanceof RedisOptions) {
  98. $options = new RedisOptions($options);
  99. }
  100. return parent::setOptions($options);
  101. }
  102. /**
  103. * Get options.
  104. *
  105. * @return RedisOptions
  106. * @see setOptions()
  107. */
  108. public function getOptions()
  109. {
  110. if (!$this->options) {
  111. $this->setOptions(new RedisOptions());
  112. }
  113. return $this->options;
  114. }
  115. /**
  116. * Internal method to get an item.
  117. *
  118. * @param string &$normalizedKey Key where to store data
  119. * @param bool &$success If the operation was successfull
  120. * @param mixed &$casToken Token
  121. * @return mixed Data on success, false on key not found
  122. * @throws Exception\RuntimeException
  123. */
  124. protected function internalGetItem(& $normalizedKey, & $success = null, & $casToken = null)
  125. {
  126. $redis = $this->getRedisResource();
  127. try {
  128. $value = $redis->get($this->namespacePrefix . $normalizedKey);
  129. } catch (RedisResourceException $e) {
  130. throw new Exception\RuntimeException($redis->getLastError(), $e->getCode(), $e);
  131. }
  132. if ($value === false) {
  133. $success = false;
  134. return null;
  135. }
  136. $success = true;
  137. $casToken = $value;
  138. return $value;
  139. }
  140. /**
  141. * Internal method to get multiple items.
  142. *
  143. * @param array &$normalizedKeys Array of keys to be obtained
  144. *
  145. * @return array Associative array of keys and values
  146. * @throws Exception\RuntimeException
  147. */
  148. protected function internalGetItems(array & $normalizedKeys)
  149. {
  150. $redis = $this->getRedisResource();
  151. $namespacedKeys = array();
  152. foreach ($normalizedKeys as & $normalizedKey) {
  153. $namespacedKeys[] = $this->namespacePrefix . $normalizedKey;
  154. }
  155. try {
  156. $results = $redis->mGet($namespacedKeys);
  157. } catch (RedisResourceException $e) {
  158. throw new Exception\RuntimeException($redis->getLastError(), $e->getCode(), $e);
  159. }
  160. //combine the key => value pairs and remove all missing values
  161. return array_filter(
  162. array_combine($normalizedKeys, $results),
  163. function ($value) {
  164. return $value !== false;
  165. }
  166. );
  167. }
  168. /**
  169. * Internal method to test if an item exists.
  170. *
  171. * @param string &$normalizedKey Normalized key which will be checked
  172. *
  173. * @return bool
  174. * @throws Exception\RuntimeException
  175. */
  176. protected function internalHasItem(& $normalizedKey)
  177. {
  178. $redis = $this->getRedisResource();
  179. try {
  180. return $redis->exists($this->namespacePrefix . $normalizedKey);
  181. } catch (RedisResourceException $e) {
  182. throw new Exception\RuntimeException($redis->getLastError(), $e->getCode(), $e);
  183. }
  184. }
  185. /**
  186. * Internal method to store an item.
  187. *
  188. * @param string &$normalizedKey Key in Redis under which value will be saved
  189. * @param mixed &$value Value to store under cache key
  190. *
  191. * @return bool
  192. * @throws Exception\RuntimeException
  193. */
  194. protected function internalSetItem(& $normalizedKey, & $value)
  195. {
  196. $redis = $this->getRedisResource();
  197. $ttl = $this->getOptions()->getTtl();
  198. try {
  199. if ($ttl) {
  200. if ($this->resourceManager->getMajorVersion($this->resourceId) < 2) {
  201. throw new Exception\UnsupportedMethodCallException("To use ttl you need version >= 2.0.0");
  202. }
  203. $success = $redis->setex($this->namespacePrefix . $normalizedKey, $ttl, $value);
  204. } else {
  205. $success = $redis->set($this->namespacePrefix . $normalizedKey, $value);
  206. }
  207. } catch (RedisResourceException $e) {
  208. throw new Exception\RuntimeException($redis->getLastError(), $e->getCode(), $e);
  209. }
  210. return $success;
  211. }
  212. /**
  213. * Internal method to store multiple items.
  214. *
  215. * @param array &$normalizedKeyValuePairs An array of normalized key/value pairs
  216. *
  217. * @return array Array of not stored keys
  218. * @throws Exception\RuntimeException
  219. */
  220. protected function internalSetItems(array & $normalizedKeyValuePairs)
  221. {
  222. $redis = $this->getRedisResource();
  223. $ttl = $this->getOptions()->getTtl();
  224. $namespacedKeyValuePairs = array();
  225. foreach ($normalizedKeyValuePairs as $normalizedKey => & $value) {
  226. $namespacedKeyValuePairs[$this->namespacePrefix . $normalizedKey] = & $value;
  227. }
  228. try {
  229. if ($ttl > 0) {
  230. //check if ttl is supported
  231. if ($this->resourceManager->getMajorVersion($this->resourceId) < 2) {
  232. throw new Exception\UnsupportedMethodCallException("To use ttl you need version >= 2.0.0");
  233. }
  234. //mSet does not allow ttl, so use transaction
  235. $transaction = $redis->multi();
  236. foreach ($namespacedKeyValuePairs as $key => $value) {
  237. $transaction->setex($key, $ttl, $value);
  238. }
  239. $success = $transaction->exec();
  240. } else {
  241. $success = $redis->mSet($namespacedKeyValuePairs);
  242. }
  243. } catch (RedisResourceException $e) {
  244. throw new Exception\RuntimeException($redis->getLastError(), $e->getCode(), $e);
  245. }
  246. if (!$success) {
  247. throw new Exception\RuntimeException($redis->getLastError());
  248. }
  249. return array();
  250. }
  251. /**
  252. * Add an item.
  253. *
  254. * @param string $normalizedKey
  255. * @param mixed $value
  256. * @return bool
  257. * @throws Exception\RuntimeException
  258. */
  259. protected function internalAddItem(& $normalizedKey, & $value)
  260. {
  261. $redis = $this->getRedisResource();
  262. try {
  263. return $redis->setnx($this->namespacePrefix . $normalizedKey, $value);
  264. } catch (RedisResourceException $e) {
  265. throw new Exception\RuntimeException($redis->getLastError(), $e->getCode(), $e);
  266. }
  267. }
  268. /**
  269. * Internal method to remove an item.
  270. *
  271. * @param string &$normalizedKey Key which will be removed
  272. *
  273. * @return bool
  274. * @throws Exception\RuntimeException
  275. */
  276. protected function internalRemoveItem(& $normalizedKey)
  277. {
  278. $redis = $this->getRedisResource();
  279. try {
  280. return (bool) $redis->delete($this->namespacePrefix . $normalizedKey);
  281. } catch (RedisResourceException $e) {
  282. throw new Exception\RuntimeException($redis->getLastError(), $e->getCode(), $e);
  283. }
  284. }
  285. /**
  286. * Internal method to increment an item.
  287. *
  288. * @param string $normalizedKey
  289. * @param int $value
  290. * @return int|bool The new value on success, false on failure
  291. * @throws Exception\RuntimeException
  292. */
  293. protected function internalIncrementItem(& $normalizedKey, & $value)
  294. {
  295. $redis = $this->getRedisResource();
  296. try {
  297. return $redis->incrBy($this->namespacePrefix . $normalizedKey, $value);
  298. } catch (RedisResourceException $e) {
  299. throw new Exception\RuntimeException($redis->getLastError(), $e->getCode(), $e);
  300. }
  301. }
  302. /**
  303. * Internal method to decrement an item.
  304. *
  305. * @param string $normalizedKey
  306. * @param int $value
  307. * @return int|bool The new value on success, false on failure
  308. * @throws Exception\RuntimeException
  309. */
  310. protected function internalDecrementItem(& $normalizedKey, & $value)
  311. {
  312. $redis = $this->getRedisResource();
  313. try {
  314. return $redis->decrBy($this->namespacePrefix . $normalizedKey, $value);
  315. } catch (RedisResourceException $e) {
  316. throw new Exception\RuntimeException($redis->getLastError(), $e->getCode(), $e);
  317. }
  318. }
  319. /**
  320. * Flush currently set DB
  321. *
  322. * @return bool
  323. * @throws Exception\RuntimeException
  324. */
  325. public function flush()
  326. {
  327. $redis = $this->getRedisResource();
  328. try {
  329. return $redis->flushDB();
  330. } catch (RedisResourceException $e) {
  331. throw new Exception\RuntimeException($redis->getLastError(), $e->getCode(), $e);
  332. }
  333. }
  334. /* TotalSpaceCapableInterface */
  335. /**
  336. * Get total space in bytes
  337. *
  338. * @return int|float
  339. */
  340. public function getTotalSpace()
  341. {
  342. $redis = $this->getRedisResource();
  343. try {
  344. $info = $redis->info();
  345. } catch (RedisResourceException $e) {
  346. throw new Exception\RuntimeException($redis->getLastError(), $e->getCode(), $e);
  347. }
  348. return $info['used_memory'];
  349. }
  350. /* status */
  351. /**
  352. * Internal method to get capabilities of this adapter
  353. *
  354. * @return Capabilities
  355. */
  356. protected function internalGetCapabilities()
  357. {
  358. if ($this->capabilities === null) {
  359. $this->capabilityMarker = new stdClass();
  360. $minTtl = $this->resourceManager->getMajorVersion($this->resourceId) < 2 ? 0 : 1;
  361. //without serialization redis supports only strings for simple
  362. //get/set methods
  363. $this->capabilities = new Capabilities(
  364. $this,
  365. $this->capabilityMarker,
  366. array(
  367. 'supportedDatatypes' => array(
  368. 'NULL' => 'string',
  369. 'boolean' => 'string',
  370. 'integer' => 'string',
  371. 'double' => 'string',
  372. 'string' => true,
  373. 'array' => false,
  374. 'object' => false,
  375. 'resource' => false,
  376. ),
  377. 'supportedMetadata' => array(),
  378. 'minTtl' => $minTtl,
  379. 'maxTtl' => 0,
  380. 'staticTtl' => true,
  381. 'ttlPrecision' => 1,
  382. 'useRequestTime' => false,
  383. 'expiredRead' => false,
  384. 'maxKeyLength' => 255,
  385. 'namespaceIsPrefix' => true,
  386. )
  387. );
  388. }
  389. return $this->capabilities;
  390. }
  391. }