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