Namespaces

  • Nette
    • Application
    • Caching
    • Collections
    • Config
    • Forms
    • IO
    • Loaders
    • Mail
    • Reflection
    • Security
    • Templates
    • Web
  • None
  • PHP

Classes

  • Cache
  • DummyStorage
  • FileStorage
  • MemcachedStorage

Interfaces

  • ICacheStorage
  • Overview
  • Namespace
  • Class
  • Tree
  • Other releases
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (https://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: class Cache extends Nette\Object implements \ArrayAccess
 24: {
 25:     /**#@+ dependency */
 26:     const PRIORITY = 'priority';
 27:     const EXPIRATION = 'expire';
 28:     const EXPIRE = 'expire';
 29:     const SLIDING = 'sliding';
 30:     const TAGS = 'tags';
 31:     const FILES = 'files';
 32:     const ITEMS = 'items';
 33:     const CONSTS = 'consts';
 34:     const CALLBACKS = 'callbacks';
 35:     const ALL = 'all';
 36:     /**#@-*/
 37: 
 38:     /** @deprecated */
 39:     const REFRESH = 'sliding';
 40: 
 41:     /** @internal */
 42:     const NAMESPACE_SEPARATOR = "\x00";
 43: 
 44:     /** @var ICacheStorage */
 45:     private $storage;
 46: 
 47:     /** @var string */
 48:     private $namespace;
 49: 
 50:     /** @var string  last query cache */
 51:     private $key;
 52: 
 53:     /** @var mixed  last query cache */
 54:     private $data;
 55: 
 56: 
 57: 
 58:     public function __construct(ICacheStorage $storage, $namespace = NULL)
 59:     {
 60:         $this->storage = $storage;
 61:         $this->namespace = (string) $namespace;
 62: 
 63:         if (strpos($this->namespace, self::NAMESPACE_SEPARATOR) !== FALSE) {
 64:             throw new \InvalidArgumentException("Namespace name contains forbidden character.");
 65:         }
 66:     }
 67: 
 68: 
 69: 
 70:     /**
 71:      * Returns cache storage.
 72:      * @return ICacheStorage
 73:      */
 74:     public function getStorage()
 75:     {
 76:         return $this->storage;
 77:     }
 78: 
 79: 
 80: 
 81:     /**
 82:      * Returns cache namespace.
 83:      * @return string
 84:      */
 85:     public function getNamespace()
 86:     {
 87:         return $this->namespace;
 88:     }
 89: 
 90: 
 91: 
 92:     /**
 93:      * Discards the internal cache.
 94:      * @return void
 95:      */
 96:     public function release()
 97:     {
 98:         $this->key = $this->data = NULL;
 99:     }
100: 
101: 
102: 
103:     /**
104:      * Writes item into the cache.
105:      * Dependencies are:
106:      * - Cache::PRIORITY => (int) priority
107:      * - Cache::EXPIRATION => (timestamp) expiration
108:      * - Cache::SLIDING => (bool) use sliding expiration?
109:      * - Cache::TAGS => (array) tags
110:      * - Cache::FILES => (array|string) file names
111:      * - Cache::ITEMS => (array|string) cache items
112:      * - Cache::CONSTS => (array|string) cache items
113:      *
114:      * @param  string key
115:      * @param  mixed  value
116:      * @param  array  dependencies
117:      * @return mixed  value itself
118:      * @throws \InvalidArgumentException
119:      */
120:     public function save($key, $data, array $dp = NULL)
121:     {
122:         if (!is_string($key) && !is_int($key)) {
123:             throw new \InvalidArgumentException("Cache key name must be string or integer, " . gettype($key) ." given.");
124:         }
125:         $this->key = (string) $key;
126:         $key = $this->namespace . self::NAMESPACE_SEPARATOR . $key;
127: 
128:         // convert expire into relative amount of seconds
129:         if (isset($dp[Cache::EXPIRATION])) {
130:             $dp[Cache::EXPIRATION] = Nette\DateTime::from($dp[Cache::EXPIRATION])->format('U') - time();
131:         }
132: 
133:         // convert FILES into CALLBACKS
134:         if (isset($dp[self::FILES])) {
135:             //clearstatcache();
136:             foreach ((array) $dp[self::FILES] as $item) {
137:                 $dp[self::CALLBACKS][] = array(array(__CLASS__, 'checkFile'), $item, @filemtime($item)); // @ - stat may fail
138:             }
139:             unset($dp[self::FILES]);
140:         }
141: 
142:         // add namespaces to items
143:         if (isset($dp[self::ITEMS])) {
144:             $dp[self::ITEMS] = (array) $dp[self::ITEMS];
145:             foreach ($dp[self::ITEMS] as $k => $item) {
146:                 $dp[self::ITEMS][$k] = $this->namespace . self::NAMESPACE_SEPARATOR . $item;
147:             }
148:         }
149: 
150:         // convert CONSTS into CALLBACKS
151:         if (isset($dp[self::CONSTS])) {
152:             foreach ((array) $dp[self::CONSTS] as $item) {
153:                 $dp[self::CALLBACKS][] = array(array(__CLASS__, 'checkConst'), $item, constant($item));
154:             }
155:             unset($dp[self::CONSTS]);
156:         }
157: 
158:         if ($data instanceof Nette\Callback || $data instanceof \Closure) {
159:             Nette\Environment::enterCriticalSection('Nette\Caching/' . $key);
160:             $data = $data->__invoke();
161:             Nette\Environment::leaveCriticalSection('Nette\Caching/' . $key);
162:         }
163: 
164:         if (is_object($data)) {
165:             $dp[self::CALLBACKS][] = array(array(__CLASS__, 'checkSerializationVersion'), get_class($data),
166:                 Nette\Reflection\ClassReflection::from($data)->getAnnotation('serializationVersion'));
167:         }
168: 
169:         $this->data = $data;
170:         if ($data === NULL) {
171:             $this->storage->remove($key);
172:         } else {
173:             $this->storage->write($key, $data, (array) $dp);
174:         }
175:         return $data;
176:     }
177: 
178: 
179: 
180:     /**
181:      * Removes items from the cache by conditions.
182:      * Conditions are:
183:      * - Cache::PRIORITY => (int) priority
184:      * - Cache::TAGS => (array) tags
185:      * - Cache::ALL => TRUE
186:      *
187:      * @param  array
188:      * @return void
189:      */
190:     public function clean(array $conds = NULL)
191:     {
192:         $this->release();
193:         $this->storage->clean((array) $conds);
194:     }
195: 
196: 
197: 
198:     /********************* interface \ArrayAccess ****************d*g**/
199: 
200: 
201: 
202:     /**
203:      * Inserts (replaces) item into the cache (\ArrayAccess implementation).
204:      * @param  string key
205:      * @param  mixed
206:      * @return void
207:      * @throws \InvalidArgumentException
208:      */
209:     public function offsetSet($key, $data)
210:     {
211:         $this->save($key, $data);
212:     }
213: 
214: 
215: 
216:     /**
217:      * Retrieves the specified item from the cache or NULL if the key is not found (\ArrayAccess implementation).
218:      * @param  string key
219:      * @return mixed|NULL
220:      * @throws \InvalidArgumentException
221:      */
222:     public function offsetGet($key)
223:     {
224:         if (!is_string($key) && !is_int($key)) {
225:             throw new \InvalidArgumentException("Cache key name must be string or integer, " . gettype($key) ." given.");
226:         }
227: 
228:         $key = (string) $key;
229:         if ($this->key === $key) {
230:             return $this->data;
231:         }
232:         $this->key = $key;
233:         $this->data = $this->storage->read($this->namespace . self::NAMESPACE_SEPARATOR . $key);
234:         return $this->data;
235:     }
236: 
237: 
238: 
239:     /**
240:      * Exists item in cache? (\ArrayAccess implementation).
241:      * @param  string key
242:      * @return bool
243:      * @throws \InvalidArgumentException
244:      */
245:     public function offsetExists($key)
246:     {
247:         return $this->offsetGet($key) !== NULL;
248:     }
249: 
250: 
251: 
252:     /**
253:      * Removes the specified item from the cache.
254:      * @param  string key
255:      * @return void
256:      * @throws \InvalidArgumentException
257:      */
258:     public function offsetUnset($key)
259:     {
260:         $this->save($key, NULL);
261:     }
262: 
263: 
264: 
265:     /********************* dependency checkers ****************d*g**/
266: 
267: 
268: 
269:     /**
270:      * Checks CALLBACKS dependencies.
271:      * @param  array
272:      * @return bool
273:      */
274:     public static function checkCallbacks($callbacks)
275:     {
276:         foreach ($callbacks as $callback) {
277:             $func = array_shift($callback);
278:             if (!call_user_func_array($func, $callback)) {
279:                 return FALSE;
280:             }
281:         }
282:         return TRUE;
283:     }
284: 
285: 
286: 
287:     /**
288:      * Checks CONSTS dependency.
289:      * @param  string
290:      * @param  mixed
291:      * @return bool
292:      */
293:     private static function checkConst($const, $value)
294:     {
295:         return defined($const) && constant($const) === $value;
296:     }
297: 
298: 
299: 
300:     /**
301:      * Checks FILES dependency.
302:      * @param  string
303:      * @param  int
304:      * @return bool
305:      */
306:     private static function checkFile($file, $time)
307:     {
308:         return @filemtime($file) == $time; // @ - stat may fail
309:     }
310: 
311: 
312: 
313:     /**
314:      * Checks object @serializationVersion label.
315:      * @param  string
316:      * @param  mixed
317:      * @return bool
318:      */
319:     private static function checkSerializationVersion($class, $value)
320:     {
321:         return Nette\Reflection\ClassReflection::from($class)->getAnnotation('serializationVersion') === $value;
322:     }
323: 
324: }
325: 
Nette Framework 0.9.7 API documentation generated by ApiGen 2.3.0