Namespaces

  • 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
  • OutputHelper

Interfaces

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