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