1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10: 11:
12:
13:
14:
15: 16: 17: 18: 19:
20: class MemcachedStorage extends Object implements ICacheStorage
21: {
22:
23: const META_CALLBACKS = 'callbacks';
24: const META_DATA = 'data';
25: const META_DELTA = 'delta';
26:
27:
28:
29: private $memcache;
30:
31:
32: private $prefix;
33:
34:
35: private $context;
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 = '', Context $context = NULL)
51: {
52: if (!self::isAvailable()) {
53: throw new NotSupportedException("PHP extension 'memcache' is not loaded.");
54: }
55:
56: $this->prefix = $prefix;
57: $this->context = $context;
58: $this->memcache = new Memcache;
59: Debug::tryError();
60: $this->memcache->connect($host, $port);
61: if (Debug::catchError($msg)) {
62: throw new InvalidStateException($msg);
63: }
64: }
65:
66:
67:
68: 69: 70: 71: 72:
73: public function read($key)
74: {
75: $key = $this->prefix . $key;
76: $meta = $this->memcache->get($key);
77: if (!$meta) return NULL;
78:
79: 80: 81: 82: 83: 84: 85:
86: 87: if (!empty($meta[self::META_CALLBACKS]) && !Cache::checkCallbacks($meta[self::META_CALLBACKS])) {
88: $this->memcache->delete($key, 0);
89: return NULL;
90: }
91:
92: if (!empty($meta[self::META_DELTA])) {
93: $this->memcache->replace($key, $meta, 0, $meta[self::META_DELTA] + time());
94: }
95:
96: return $meta[self::META_DATA];
97: }
98:
99:
100:
101: 102: 103: 104: 105: 106: 107:
108: public function write($key, $data, array $dp)
109: {
110: if (isset($dp[Cache::ITEMS])) {
111: throw new NotSupportedException('Dependent items are not supported by MemcachedStorage.');
112: }
113:
114: $meta = array(
115: self::META_DATA => $data,
116: );
117:
118: $expire = 0;
119: if (isset($dp[Cache::EXPIRE])) {
120: $expire = (int) $dp[Cache::EXPIRE];
121: if (!empty($dp[Cache::SLIDING])) {
122: $meta[self::META_DELTA] = $expire; 123: }
124: }
125:
126: if (isset($dp[Cache::CALLBACKS])) {
127: $meta[self::META_CALLBACKS] = $dp[Cache::CALLBACKS];
128: }
129:
130: if (isset($dp[Cache::TAGS]) || isset($dp[Cache::PRIORITY])) {
131: if (!$this->context) {
132: throw new InvalidStateException('CacheJournal has not been provided.');
133: }
134: $this->getJournal()->write($this->prefix . $key, $dp);
135: }
136:
137: $this->memcache->set($this->prefix . $key, $meta, 0, $expire);
138: }
139:
140:
141:
142: 143: 144: 145: 146:
147: public function remove($key)
148: {
149: $this->memcache->delete($this->prefix . $key, 0);
150: }
151:
152:
153:
154: 155: 156: 157: 158:
159: public function clean(array $conds)
160: {
161: if (!empty($conds[Cache::ALL])) {
162: $this->memcache->flush();
163:
164: } elseif ($this->context) {
165: foreach ($this->getJournal()->clean($conds) as $entry) {
166: $this->memcache->delete($entry, 0);
167: }
168: }
169: }
170:
171:
172:
173: 174: 175:
176: protected function getJournal()
177: {
178: return $this->context->getService('Nette\\Caching\\ICacheJournal');
179: }
180:
181: }
182: