Packages

  • Nette
    • Application
      • Diagnostics
      • Responses
      • Routers
      • UI
    • Caching
      • Storages
    • ComponentModel
    • Config
      • Adapters
      • Extensions
    • Database
      • Diagnostics
      • Drivers
      • Reflection
      • Table
    • DI
      • Diagnostics
    • Diagnostics
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Latte
      • Macros
    • Loaders
    • Localization
    • Mail
    • Reflection
    • Security
      • Diagnostics
    • Templating
    • Utils
      • PhpGenerator
  • NetteModule
  • None
  • PHP

Classes

  • NCache
  • NCachingHelper

Interfaces

  • ICacheStorage
  • Overview
  • Package
  • Class
  • Tree
  • Deprecated
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (http://nette.org)
  5:  *
  6:  * Copyright (c) 2004 David Grudl (http://davidgrudl.com)
  7:  *
  8:  * For the full copyright and license information, please view
  9:  * the file license.txt that was distributed with this source code.
 10:  * @package Nette\Caching
 11:  */
 12: 
 13: 
 14: 
 15: /**
 16:  * Implements the cache for a application.
 17:  *
 18:  * @author     David Grudl
 19:  *
 20:  * @property-read ICacheStorage $storage
 21:  * @property-read string $namespace
 22:  * @package Nette\Caching
 23:  */
 24: class NCache extends NObject implements ArrayAccess
 25: {
 26:     /** dependency */
 27:     const PRIORITY = 'priority',
 28:         EXPIRATION = 'expire',
 29:         EXPIRE = 'expire',
 30:         SLIDING = 'sliding',
 31:         TAGS = 'tags',
 32:         FILES = 'files',
 33:         ITEMS = 'items',
 34:         CONSTS = 'consts',
 35:         CALLBACKS = 'callbacks',
 36:         ALL = 'all';
 37: 
 38:     /** @internal */
 39:     const NAMESPACE_SEPARATOR = "\x00";
 40: 
 41:     /** @var ICacheStorage */
 42:     private $storage;
 43: 
 44:     /** @var string */
 45:     private $namespace;
 46: 
 47:     /** @var string  last query cache used by offsetGet() */
 48:     private $key;
 49: 
 50:     /** @var mixed  last query cache used by offsetGet()  */
 51:     private $data;
 52: 
 53: 
 54: 
 55:     public function __construct(ICacheStorage $storage, $namespace = NULL)
 56:     {
 57:         $this->storage = $storage;
 58:         $this->namespace = $namespace . self::NAMESPACE_SEPARATOR;
 59:     }
 60: 
 61: 
 62: 
 63:     /**
 64:      * Returns cache storage.
 65:      * @return ICacheStorage
 66:      */
 67:     public function getStorage()
 68:     {
 69:         return $this->storage;
 70:     }
 71: 
 72: 
 73: 
 74:     /**
 75:      * Returns cache namespace.
 76:      * @return string
 77:      */
 78:     public function getNamespace()
 79:     {
 80:         return (string) substr($this->namespace, 0, -1);
 81:     }
 82: 
 83: 
 84: 
 85:     /**
 86:      * Returns new nested cache object.
 87:      * @param  string
 88:      * @return NCache
 89:      */
 90:     public function derive($namespace)
 91:     {
 92:         $derived = new self($this->storage, $this->namespace . $namespace);
 93:         return $derived;
 94:     }
 95: 
 96: 
 97: 
 98:     /**
 99:      * Reads the specified item from the cache or generate it.
100:      * @param  mixed key
101:      * @param  callable
102:      * @return mixed|NULL
103:      */
104:     public function load($key, $fallback = NULL)
105:     {
106:         $data = $this->storage->read($this->generateKey($key));
107:         if ($data === NULL && $fallback) {
108:             return $this->save($key, new NCallback($fallback));
109:         }
110:         return $data;
111:     }
112: 
113: 
114: 
115:     /**
116:      * Writes item into the cache.
117:      * Dependencies are:
118:      * - NCache::PRIORITY => (int) priority
119:      * - NCache::EXPIRATION => (timestamp) expiration
120:      * - NCache::SLIDING => (bool) use sliding expiration?
121:      * - NCache::TAGS => (array) tags
122:      * - NCache::FILES => (array|string) file names
123:      * - NCache::ITEMS => (array|string) cache items
124:      * - NCache::CONSTS => (array|string) cache items
125:      *
126:      * @param  mixed  key
127:      * @param  mixed  value
128:      * @param  array  dependencies
129:      * @return mixed  value itself
130:      * @throws InvalidArgumentException
131:      */
132:     public function save($key, $data, array $dependencies = NULL)
133:     {
134:         $this->release();
135:         $key = $this->generateKey($key);
136: 
137:         if ($data instanceof NCallback || $data instanceof Closure) {
138:             $this->storage->lock($key);
139:             $data = NCallback::create($data)->invokeArgs(array(&$dependencies));
140:         }
141: 
142:         if ($data === NULL) {
143:             $this->storage->remove($key);
144:         } else {
145:             $this->storage->write($key, $data, $this->completeDependencies($dependencies, $data));
146:             return $data;
147:         }
148:     }
149: 
150: 
151: 
152:     private function completeDependencies($dp, $data)
153:     {
154:         if (is_object($data)) {
155:             $dp[self::CALLBACKS][] = array(array(__CLASS__, 'checkSerializationVersion'), get_class($data),
156:                 NClassReflection::from($data)->getAnnotation('serializationVersion'));
157:         }
158: 
159:         // convert expire into relative amount of seconds
160:         if (isset($dp[NCache::EXPIRATION])) {
161:             $dp[NCache::EXPIRATION] = NDateTime53::from($dp[NCache::EXPIRATION])->format('U') - time();
162:         }
163: 
164:         // convert FILES into CALLBACKS
165:         if (isset($dp[self::FILES])) {
166:             //clearstatcache();
167:             foreach (array_unique((array) $dp[self::FILES]) as $item) {
168:                 $dp[self::CALLBACKS][] = array(array(__CLASS__, 'checkFile'), $item, @filemtime($item)); // @ - stat may fail
169:             }
170:             unset($dp[self::FILES]);
171:         }
172: 
173:         // add namespaces to items
174:         if (isset($dp[self::ITEMS])) {
175:             $dp[self::ITEMS] = array_unique(array_map(array($this, 'generateKey'), (array) $dp[self::ITEMS]));
176:         }
177: 
178:         // convert CONSTS into CALLBACKS
179:         if (isset($dp[self::CONSTS])) {
180:             foreach (array_unique((array) $dp[self::CONSTS]) as $item) {
181:                 $dp[self::CALLBACKS][] = array(array(__CLASS__, 'checkConst'), $item, constant($item));
182:             }
183:             unset($dp[self::CONSTS]);
184:         }
185: 
186:         if (!is_array($dp)) {
187:             $dp = array();
188:         }
189:         return $dp;
190:     }
191: 
192: 
193: 
194:     /**
195:      * Removes item from the cache.
196:      * @param  mixed  key
197:      * @return void
198:      */
199:     public function remove($key)
200:     {
201:         $this->save($key, NULL);
202:     }
203: 
204: 
205: 
206:     /**
207:      * Removes items from the cache by conditions.
208:      * Conditions are:
209:      * - NCache::PRIORITY => (int) priority
210:      * - NCache::TAGS => (array) tags
211:      * - NCache::ALL => TRUE
212:      * @return void
213:      */
214:     public function clean(array $conditions = NULL)
215:     {
216:         $this->release();
217:         $this->storage->clean((array) $conditions);
218:     }
219: 
220: 
221: 
222:     /**
223:      * Caches results of function/method calls.
224:      * @param  mixed
225:      * @return mixed
226:      */
227:     public function call($function)
228:     {
229:         $key = func_get_args();
230:         return $this->load($key, create_function('', 'extract($GLOBALS[0]['.array_push($GLOBALS[0], array('function'=>$function,'key'=> $key)).'-1], EXTR_REFS);
231:             array_shift($key);
232:             return NCallback::create($function)->invokeArgs($key);
233:         '));
234:     }
235: 
236: 
237: 
238:     /**
239:      * Caches results of function/method calls.
240:      * @param  mixed
241:      * @param  array  dependencies
242:      * @return NClosure
243:      */
244:     public function wrap($function, array $dependencies = NULL)
245:     {
246:         $cache = $this;
247:         return create_function('', 'extract($GLOBALS[0]['.array_push($GLOBALS[0], array('cache'=>$cache,'function'=> $function,'dependencies'=> $dependencies)).'-1], EXTR_REFS);
248:             $_args=func_get_args(); $key = array($function, $_args);
249:             $data = $cache->load($key);
250:             if ($data === NULL) {
251:                 $data = $cache->save($key, NCallback::create($function)->invokeArgs($key[1]), $dependencies);
252:             }
253:             return $data;
254:         ');
255:     }
256: 
257: 
258: 
259:     /**
260:      * Starts the output cache.
261:      * @param  mixed  key
262:      * @return NCachingHelper|NULL
263:      */
264:     public function start($key)
265:     {
266:         $data = $this->load($key);
267:         if ($data === NULL) {
268:             return new NCachingHelper($this, $key);
269:         }
270:         echo $data;
271:     }
272: 
273: 
274: 
275:     /**
276:      * Generates internal cache key.
277:      *
278:      * @param  string
279:      * @return string
280:      */
281:     protected function generateKey($key)
282:     {
283:         return $this->namespace . md5(is_scalar($key) ? $key : serialize($key));
284:     }
285: 
286: 
287: 
288:     /********************* interface ArrayAccess ****************d*g**/
289: 
290: 
291: 
292:     /**
293:      * Inserts (replaces) item into the cache (ArrayAccess implementation).
294:      * @param  mixed key
295:      * @param  mixed
296:      * @return void
297:      * @throws InvalidArgumentException
298:      */
299:     public function offsetSet($key, $data)
300:     {
301:         $this->save($key, $data);
302:     }
303: 
304: 
305: 
306:     /**
307:      * Retrieves the specified item from the cache or NULL if the key is not found (ArrayAccess implementation).
308:      * @param  mixed key
309:      * @return mixed|NULL
310:      * @throws InvalidArgumentException
311:      */
312:     public function offsetGet($key)
313:     {
314:         $key = is_scalar($key) ? (string) $key : serialize($key);
315:         if ($this->key !== $key) {
316:             $this->key = $key;
317:             $this->data = $this->load($key);
318:         }
319:         return $this->data;
320:     }
321: 
322: 
323: 
324:     /**
325:      * Exists item in cache? (ArrayAccess implementation).
326:      * @param  mixed key
327:      * @return bool
328:      * @throws InvalidArgumentException
329:      */
330:     public function offsetExists($key)
331:     {
332:         $this->release();
333:         return $this->offsetGet($key) !== NULL;
334:     }
335: 
336: 
337: 
338:     /**
339:      * Removes the specified item from the cache.
340:      * @param  mixed key
341:      * @return void
342:      * @throws InvalidArgumentException
343:      */
344:     public function offsetUnset($key)
345:     {
346:         $this->save($key, NULL);
347:     }
348: 
349: 
350: 
351:     /**
352:      * Discards the internal cache used by ArrayAccess.
353:      * @return void
354:      */
355:     public function release()
356:     {
357:         $this->key = $this->data = NULL;
358:     }
359: 
360: 
361: 
362:     /********************* dependency checkers ****************d*g**/
363: 
364: 
365: 
366:     /**
367:      * Checks CALLBACKS dependencies.
368:      * @param  array
369:      * @return bool
370:      */
371:     public static function checkCallbacks($callbacks)
372:     {
373:         foreach ($callbacks as $callback) {
374:             $func = array_shift($callback);
375:             if (!call_user_func_array($func, $callback)) {
376:                 return FALSE;
377:             }
378:         }
379:         return TRUE;
380:     }
381: 
382: 
383: 
384:     /**
385:      * Checks CONSTS dependency.
386:      * @param  string
387:      * @param  mixed
388:      * @return bool
389:      */
390:     private static function checkConst($const, $value)
391:     {
392:         return defined($const) && constant($const) === $value;
393:     }
394: 
395: 
396: 
397:     /**
398:      * Checks FILES dependency.
399:      * @param  string
400:      * @param  int
401:      * @return bool
402:      */
403:     private static function checkFile($file, $time)
404:     {
405:         return @filemtime($file) == $time; // @ - stat may fail
406:     }
407: 
408: 
409: 
410:     /**
411:      * Checks object @serializationVersion label.
412:      * @param  string
413:      * @param  mixed
414:      * @return bool
415:      */
416:     private static function checkSerializationVersion($class, $value)
417:     {
418:         return NClassReflection::from($class)->getAnnotation('serializationVersion') === $value;
419:     }
420: 
421: }
422: 
Nette Framework 2.0.10 (for PHP 5.2, prefixed) API API documentation generated by ApiGen 2.8.0