PageRenderTime 36ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 0ms

/www/libs/nette-dev/Caching/Cache.php

https://github.com/bazo/Mokuji
PHP | 329 lines | 144 code | 69 blank | 116 comment | 22 complexity | 922214c7f4bea91be96fec37732551bc MD5 | raw file
Possible License(s): BSD-3-Clause, MIT
  1. <?php
  2. /**
  3. * Nette Framework
  4. *
  5. * @copyright Copyright (c) 2004, 2010 David Grudl
  6. * @license http://nettephp.com/license Nette license
  7. * @link http://nettephp.com
  8. * @category Nette
  9. * @package Nette\Caching
  10. */
  11. /**
  12. * Implements the cache for a application.
  13. *
  14. * @copyright Copyright (c) 2004, 2010 David Grudl
  15. * @package Nette\Caching
  16. */
  17. class Cache extends Object implements ArrayAccess
  18. {
  19. /**#@+ dependency */
  20. const PRIORITY = 'priority';
  21. const EXPIRE = 'expire';
  22. const SLIDING = 'sliding';
  23. const TAGS = 'tags';
  24. const FILES = 'files';
  25. const ITEMS = 'items';
  26. const CONSTS = 'consts';
  27. const CALLBACKS = 'callbacks';
  28. const ALL = 'all';
  29. /**#@-*/
  30. /** @ignore internal */
  31. const NAMESPACE_SEPARATOR = "\x00";
  32. /** @var ICacheStorage */
  33. private $storage;
  34. /** @var string */
  35. private $namespace;
  36. /** @var string last query cache */
  37. private $key;
  38. /** @var mixed last query cache */
  39. private $data;
  40. public function __construct(ICacheStorage $storage, $namespace = NULL)
  41. {
  42. $this->storage = $storage;
  43. $this->namespace = (string) $namespace;
  44. if (strpos($this->namespace, self::NAMESPACE_SEPARATOR) !== FALSE) {
  45. throw new InvalidArgumentException("Namespace name contains forbidden character.");
  46. }
  47. }
  48. /**
  49. * Returns cache storage.
  50. * @return ICacheStorage
  51. */
  52. public function getStorage()
  53. {
  54. return $this->storage;
  55. }
  56. /**
  57. * Returns cache namespace.
  58. * @return string
  59. */
  60. public function getNamespace()
  61. {
  62. return $this->namespace;
  63. }
  64. /**
  65. * Discards the internal cache.
  66. * @return void
  67. */
  68. public function release()
  69. {
  70. $this->key = $this->data = NULL;
  71. }
  72. /**
  73. * Writes item into the cache.
  74. * Dependencies are:
  75. * - Cache::PRIORITY => (int) priority
  76. * - Cache::EXPIRE => (timestamp) expiration
  77. * - Cache::SLIDING => (bool) use sliding expiration?
  78. * - Cache::TAGS => (array) tags
  79. * - Cache::FILES => (array|string) file names
  80. * - Cache::ITEMS => (array|string) cache items
  81. * - Cache::CONSTS => (array|string) cache items
  82. *
  83. * @param string key
  84. * @param mixed value
  85. * @param array dependencies
  86. * @return mixed value itself
  87. * @throws InvalidArgumentException
  88. */
  89. public function save($key, $data, array $dp = NULL)
  90. {
  91. if (!is_string($key) && !is_int($key)) {
  92. throw new InvalidArgumentException("Cache key name must be string or integer, " . gettype($key) ." given.");
  93. }
  94. // convert expire into relative amount of seconds
  95. if (!empty($dp[Cache::EXPIRE])) {
  96. $dp[Cache::EXPIRE] = Tools::createDateTime($dp[Cache::EXPIRE])->format('U') - time();
  97. }
  98. // convert FILES into CALLBACKS
  99. if (isset($dp[self::FILES])) {
  100. //clearstatcache();
  101. foreach ((array) $dp[self::FILES] as $item) {
  102. $dp[self::CALLBACKS][] = array(array(__CLASS__, 'checkFile'), $item, @filemtime($item)); // intentionally @
  103. }
  104. unset($dp[self::FILES]);
  105. }
  106. // add namespaces to items
  107. if (isset($dp[self::ITEMS])) {
  108. $dp[self::ITEMS] = (array) $dp[self::ITEMS];
  109. foreach ($dp[self::ITEMS] as $k => $item) {
  110. $dp[self::ITEMS][$k] = $this->namespace . self::NAMESPACE_SEPARATOR . $item;
  111. }
  112. }
  113. // convert CONSTS into CALLBACKS
  114. if (isset($dp[self::CONSTS])) {
  115. foreach ((array) $dp[self::CONSTS] as $item) {
  116. $dp[self::CALLBACKS][] = array(array(__CLASS__, 'checkConst'), $item, constant($item));
  117. }
  118. unset($dp[self::CONSTS]);
  119. }
  120. if (is_object($data)) {
  121. $dp[self::CALLBACKS][] = array(array(__CLASS__, 'checkSerializationVersion'), get_class($data),
  122. ClassReflection::from($data)->getAnnotation('serializationVersion'));
  123. }
  124. $this->key = NULL;
  125. $this->storage->write(
  126. $this->namespace . self::NAMESPACE_SEPARATOR . $key,
  127. $data,
  128. (array) $dp
  129. );
  130. return $data;
  131. }
  132. /**
  133. * Removes items from the cache by conditions.
  134. * Conditions are:
  135. * - Cache::PRIORITY => (int) priority
  136. * - Cache::TAGS => (array) tags
  137. * - Cache::ALL => TRUE
  138. *
  139. * @param array
  140. * @return void
  141. */
  142. public function clean(array $conds = NULL)
  143. {
  144. $this->storage->clean((array) $conds);
  145. }
  146. /********************* interface \ArrayAccess ****************d*g**/
  147. /**
  148. * Inserts (replaces) item into the cache (\ArrayAccess implementation).
  149. * @param string key
  150. * @param mixed
  151. * @return void
  152. * @throws InvalidArgumentException
  153. */
  154. public function offsetSet($key, $data)
  155. {
  156. if (!is_string($key) && !is_int($key)) { // prevents NULL
  157. throw new InvalidArgumentException("Cache key name must be string or integer, " . gettype($key) ." given.");
  158. }
  159. $this->key = $this->data = NULL;
  160. if ($data === NULL) {
  161. $this->storage->remove($this->namespace . self::NAMESPACE_SEPARATOR . $key);
  162. } else {
  163. $this->storage->write($this->namespace . self::NAMESPACE_SEPARATOR . $key, $data, array());
  164. }
  165. }
  166. /**
  167. * Retrieves the specified item from the cache or NULL if the key is not found (\ArrayAccess implementation).
  168. * @param string key
  169. * @return mixed|NULL
  170. * @throws InvalidArgumentException
  171. */
  172. public function offsetGet($key)
  173. {
  174. if (!is_string($key) && !is_int($key)) {
  175. throw new InvalidArgumentException("Cache key name must be string or integer, " . gettype($key) ." given.");
  176. }
  177. $key = (string) $key;
  178. if ($this->key === $key) {
  179. return $this->data;
  180. }
  181. $this->key = $key;
  182. $this->data = $this->storage->read($this->namespace . self::NAMESPACE_SEPARATOR . $key);
  183. return $this->data;
  184. }
  185. /**
  186. * Exists item in cache? (\ArrayAccess implementation).
  187. * @param string key
  188. * @return bool
  189. * @throws InvalidArgumentException
  190. */
  191. public function offsetExists($key)
  192. {
  193. if (!is_string($key) && !is_int($key)) {
  194. throw new InvalidArgumentException("Cache key name must be string or integer, " . gettype($key) ." given.");
  195. }
  196. $this->key = (string) $key;
  197. $this->data = $this->storage->read($this->namespace . self::NAMESPACE_SEPARATOR . $key);
  198. return $this->data !== NULL;
  199. }
  200. /**
  201. * Removes the specified item from the cache.
  202. * @param string key
  203. * @return void
  204. * @throws InvalidArgumentException
  205. */
  206. public function offsetUnset($key)
  207. {
  208. if (!is_string($key) && !is_int($key)) {
  209. throw new InvalidArgumentException("Cache key name must be string or integer, " . gettype($key) ." given.");
  210. }
  211. $this->key = $this->data = NULL;
  212. $this->storage->remove($this->namespace . self::NAMESPACE_SEPARATOR . $key);
  213. }
  214. /********************* dependency checkers ****************d*g**/
  215. /**
  216. * Checks CALLBACKS dependencies.
  217. * @param array
  218. * @return bool
  219. */
  220. public static function checkCallbacks($callbacks)
  221. {
  222. foreach ($callbacks as $callback) {
  223. $func = array_shift($callback);
  224. if (!call_user_func_array($func, $callback)) {
  225. return FALSE;
  226. }
  227. }
  228. return TRUE;
  229. }
  230. /**
  231. * Checks CONSTS dependency.
  232. * @param string
  233. * @param mixed
  234. * @return bool
  235. */
  236. private static function checkConst($const, $value)
  237. {
  238. return defined($const) && constant($const) === $value;
  239. }
  240. /**
  241. * Checks FILES dependency.
  242. * @param string
  243. * @param int
  244. * @return bool
  245. */
  246. private static function checkFile($file, $time)
  247. {
  248. return @filemtime($file) == $time; // intentionally @
  249. }
  250. /**
  251. * Checks object @serializationVersion label.
  252. * @param string
  253. * @param mixed
  254. * @return bool
  255. */
  256. private static function checkSerializationVersion($class, $value)
  257. {
  258. return ClassReflection::from($class)->getAnnotation('serializationVersion') === $value;
  259. }
  260. }