Source for file Cache.php

Documentation is available at Cache.php

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