1: <?php
  2: 
  3:   4:   5:   6:   7:   8:   9:  10: 
 11: 
 12: namespace Nette\Caching;
 13: 
 14: use Nette;
 15: 
 16: 
 17: 
 18:  19:  20:  21:  22: 
 23: class MemcachedStorage extends Nette\Object implements ICacheStorage
 24: {
 25:     
 26:     const META_CALLBACKS = 'callbacks';
 27:     const META_DATA = 'data';
 28:     const META_DELTA = 'delta';
 29:     
 30: 
 31:     
 32:     private $memcache;
 33: 
 34:     
 35:     private $prefix;
 36: 
 37: 
 38: 
 39:      40:  41:  42: 
 43:     public static function isAvailable()
 44:     {
 45:         return extension_loaded('memcache');
 46:     }
 47: 
 48: 
 49: 
 50:     public function __construct($host = 'localhost', $port = 11211, $prefix = '')
 51:     {
 52:         if (!self::isAvailable()) {
 53:             throw new \Exception("PHP extension 'memcache' is not loaded.");
 54:         }
 55: 
 56:         $this->prefix = $prefix;
 57:         $this->memcache = new \Memcache;
 58:         $this->memcache->connect($host, $port);
 59:     }
 60: 
 61: 
 62: 
 63:      64:  65:  66:  67: 
 68:     public function read($key)
 69:     {
 70:         $key = $this->prefix . $key;
 71:         $meta = $this->memcache->get($key);
 72:         if (!$meta) return NULL;
 73: 
 74:         
 75:         
 76:         
 77:         
 78:         
 79:         
 80: 
 81:         
 82:         if (!empty($meta[self::META_CALLBACKS]) && !Cache::checkCallbacks($meta[self::META_CALLBACKS])) {
 83:             $this->memcache->delete($key, 0);
 84:             return NULL;
 85:         }
 86: 
 87:         if (!empty($meta[self::META_DELTA])) {
 88:             $this->memcache->replace($key, $meta, 0, $meta[self::META_DELTA] + time());
 89:         }
 90: 
 91:         return $meta[self::META_DATA];
 92:     }
 93: 
 94: 
 95: 
 96:      97:  98:  99: 100: 101: 102: 
103:     public function write($key, $data, array $dp)
104:     {
105:         if (!empty($dp[Cache::TAGS]) || isset($dp[Cache::PRIORITY]) || !empty($dp[Cache::ITEMS])) {
106:             throw new \NotSupportedException('Tags, priority and dependent items are not supported by MemcachedStorage.');
107:         }
108: 
109:         $meta = array(
110:             self::META_DATA => $data,
111:         );
112: 
113:         $expire = 0;
114:         if (isset($dp[Cache::EXPIRATION])) {
115:             $expire = (int) $dp[Cache::EXPIRATION];
116:             if (!empty($dp[Cache::SLIDING])) {
117:                 $meta[self::META_DELTA] = $expire; 
118:             }
119:         }
120: 
121:         if (isset($dp[Cache::CALLBACKS])) {
122:             $meta[self::META_CALLBACKS] = $dp[Cache::CALLBACKS];
123:         }
124: 
125:         $this->memcache->set($this->prefix . $key, $meta, 0, $expire);
126:     }
127: 
128: 
129: 
130:     131: 132: 133: 134: 
135:     public function remove($key)
136:     {
137:         $this->memcache->delete($this->prefix . $key, 0);
138:     }
139: 
140: 
141: 
142:     143: 144: 145: 146: 
147:     public function clean(array $conds)
148:     {
149:         if (!empty($conds[Cache::ALL])) {
150:             $this->memcache->flush();
151: 
152:         } elseif (isset($conds[Cache::TAGS]) || isset($conds[Cache::PRIORITY])) {
153:             throw new \NotSupportedException('Tags and priority is not supported by MemcachedStorage.');
154:         }
155:     }
156: 
157: }
158: