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

  • Cache
  • CachingHelper

Interfaces

  • ICacheStorage
  • Overview
  • Package
  • Class
  • Tree
  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 Cache extends Object 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 Cache
 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, callback($fallback));
109:         }
110:         return $data;
111:     }
112: 
113: 
114: 
115:     /**
116:      * Writes item into the cache.
117:      * Dependencies are:
118:      * - Cache::PRIORITY => (int) priority
119:      * - Cache::EXPIRATION => (timestamp) expiration
120:      * - Cache::SLIDING => (bool) use sliding expiration?
121:      * - Cache::TAGS => (array) tags
122:      * - Cache::FILES => (array|string) file names
123:      * - Cache::ITEMS => (array|string) cache items
124:      * - Cache::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 $dp = NULL)
133:     {
134:         $this->release();
135:         $key = $this->generateKey($key);
136: 
137:         if ($data instanceof Callback || $data instanceof Closure) {
138:             $this->storage->lock($key);
139:             $data = callback($data)->invokeArgs(array(&$dp));
140:         }
141: 
142:         if ($data === NULL) {
143:             $this->storage->remove($key);
144:         } else {
145:             $this->storage->write($key, $data, $this->completeDependencies($dp, $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:                 ClassReflection::from($data)->getAnnotation('serializationVersion'));
157:         }
158: 
159:         // convert expire into relative amount of seconds
160:         if (isset($dp[Cache::EXPIRATION])) {
161:             $dp[Cache::EXPIRATION] = DateTime53::from($dp[Cache::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) $dp[self::ITEMS]);
176:             foreach ($dp[self::ITEMS] as $k => $item) {
177:                 $dp[self::ITEMS][$k] = $this->generateKey($item);
178:             }
179:         }
180: 
181:         // convert CONSTS into CALLBACKS
182:         if (isset($dp[self::CONSTS])) {
183:             foreach (array_unique((array) $dp[self::CONSTS]) as $item) {
184:                 $dp[self::CALLBACKS][] = array(array(__CLASS__, 'checkConst'), $item, constant($item));
185:             }
186:             unset($dp[self::CONSTS]);
187:         }
188: 
189:         if (!is_array($dp)) {
190:             $dp = array();
191:         }
192:         return $dp;
193:     }
194: 
195: 
196: 
197:     /**
198:      * Removes item from the cache.
199:      * @param  mixed  key
200:      * @return void
201:      */
202:     public function remove($key)
203:     {
204:         $this->save($key, NULL);
205:     }
206: 
207: 
208: 
209:     /**
210:      * Removes items from the cache by conditions.
211:      * Conditions are:
212:      * - Cache::PRIORITY => (int) priority
213:      * - Cache::TAGS => (array) tags
214:      * - Cache::ALL => TRUE
215:      *
216:      * @param  array
217:      * @return void
218:      */
219:     public function clean(array $conds = NULL)
220:     {
221:         $this->release();
222:         $this->storage->clean((array) $conds);
223:     }
224: 
225: 
226: 
227:     /**
228:      * Caches results of function/method calls.
229:      * @param  mixed
230:      * @return mixed
231:      */
232:     public function call($function)
233:     {
234:         $key = func_get_args();
235:         return $this->load($key, create_function('', 'extract(NCFix::$vars['.NCFix::uses(array('function'=>$function,'key'=> $key)).'], EXTR_REFS);
236:             array_shift($key);
237:             return callback($function)->invokeArgs($key);
238:         '));
239:     }
240: 
241: 
242: 
243:     /**
244:      * Caches results of function/method calls.
245:      * @param  mixed
246:      * @param  array  dependencies
247:      * @return Closure
248:      */
249:     public function wrap($function, array $dp = NULL)
250:     {
251:         $cache = $this;
252:         return create_function('', 'extract(NCFix::$vars['.NCFix::uses(array('cache'=>$cache,'function'=> $function,'dp'=> $dp)).'], EXTR_REFS);
253:             $key = array($function, func_get_args());
254:             $data = $cache->load($key);
255:             if ($data === NULL) {
256:                 $data = $cache->save($key, callback($function)->invokeArgs($key[1]), $dp);
257:             }
258:             return $data;
259:         ');
260:     }
261: 
262: 
263: 
264:     /**
265:      * Starts the output cache.
266:      * @param  mixed  key
267:      * @return CachingHelper|NULL
268:      */
269:     public function start($key)
270:     {
271:         $data = $this->load($key);
272:         if ($data === NULL) {
273:             return new CachingHelper($this, $key);
274:         }
275:         echo $data;
276:     }
277: 
278: 
279: 
280:     /**
281:      * Generates internal cache key.
282:      *
283:      * @param  string
284:      * @return string
285:      */
286:     protected function generateKey($key)
287:     {
288:         return $this->namespace . md5(is_scalar($key) ? $key : serialize($key));
289:     }
290: 
291: 
292: 
293:     /********************* interface ArrayAccess ****************d*g**/
294: 
295: 
296: 
297:     /**
298:      * Inserts (replaces) item into the cache (ArrayAccess implementation).
299:      * @param  mixed key
300:      * @param  mixed
301:      * @return void
302:      * @throws InvalidArgumentException
303:      */
304:     public function offsetSet($key, $data)
305:     {
306:         $this->save($key, $data);
307:     }
308: 
309: 
310: 
311:     /**
312:      * Retrieves the specified item from the cache or NULL if the key is not found (ArrayAccess implementation).
313:      * @param  mixed key
314:      * @return mixed|NULL
315:      * @throws InvalidArgumentException
316:      */
317:     public function offsetGet($key)
318:     {
319:         $key = is_scalar($key) ? (string) $key : serialize($key);
320:         if ($this->key !== $key) {
321:             $this->key = $key;
322:             $this->data = $this->load($key);
323:         }
324:         return $this->data;
325:     }
326: 
327: 
328: 
329:     /**
330:      * Exists item in cache? (ArrayAccess implementation).
331:      * @param  mixed key
332:      * @return bool
333:      * @throws InvalidArgumentException
334:      */
335:     public function offsetExists($key)
336:     {
337:         $this->release();
338:         return $this->offsetGet($key) !== NULL;
339:     }
340: 
341: 
342: 
343:     /**
344:      * Removes the specified item from the cache.
345:      * @param  mixed key
346:      * @return void
347:      * @throws InvalidArgumentException
348:      */
349:     public function offsetUnset($key)
350:     {
351:         $this->save($key, NULL);
352:     }
353: 
354: 
355: 
356:     /**
357:      * Discards the internal cache used by ArrayAccess.
358:      * @return void
359:      */
360:     public function release()
361:     {
362:         $this->key = $this->data = NULL;
363:     }
364: 
365: 
366: 
367:     /********************* dependency checkers ****************d*g**/
368: 
369: 
370: 
371:     /**
372:      * Checks CALLBACKS dependencies.
373:      * @param  array
374:      * @return bool
375:      */
376:     public static function checkCallbacks($callbacks)
377:     {
378:         foreach ($callbacks as $callback) {
379:             $func = array_shift($callback);
380:             if (!call_user_func_array($func, $callback)) {
381:                 return FALSE;
382:             }
383:         }
384:         return TRUE;
385:     }
386: 
387: 
388: 
389:     /**
390:      * Checks CONSTS dependency.
391:      * @param  string
392:      * @param  mixed
393:      * @return bool
394:      */
395:     private static function checkConst($const, $value)
396:     {
397:         return defined($const) && constant($const) === $value;
398:     }
399: 
400: 
401: 
402:     /**
403:      * Checks FILES dependency.
404:      * @param  string
405:      * @param  int
406:      * @return bool
407:      */
408:     private static function checkFile($file, $time)
409:     {
410:         return @filemtime($file) == $time; // @ - stat may fail
411:     }
412: 
413: 
414: 
415:     /**
416:      * Checks object @serializationVersion label.
417:      * @param  string
418:      * @param  mixed
419:      * @return bool
420:      */
421:     private static function checkSerializationVersion($class, $value)
422:     {
423:         return ClassReflection::from($class)->getAnnotation('serializationVersion') === $value;
424:     }
425: 
426: }
427: 
Nette Framework 2.0.3 (for PHP 5.2, un-prefixed) API API documentation generated by ApiGen 2.7.0