Overview

Namespaces

  • Budovy
  • Kdyby
    • BootstrapFormRenderer
      • DI
      • Latte
  • Nette
    • Application
      • Diagnostics
      • Responses
      • Routers
      • UI
    • Caching
      • Storages
    • ComponentModel
    • Database
      • Diagnostics
      • Drivers
      • Reflection
      • Table
    • DI
      • Config
        • Adapters
      • Diagnostics
      • Extensions
    • Diagnostics
    • Forms
      • Controls
      • Rendering
    • Http
      • Diagnostics
    • Iterators
    • Latte
      • Macros
    • Loaders
    • Localization
    • Mail
    • PhpGenerator
    • Reflection
    • Security
      • Diagnostics
    • Templating
    • Utils
  • NetteModule
  • Nextras
    • Datagrid
  • None
  • PHP
  • Tester
    • CodeCoverage
    • Runner
      • Output
  • Vodacek
    • Forms
      • Controls
  • WebLoader
    • Filter
    • Nette

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