Namespaces

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