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: private $context;
39:
40:
41:
42: 43: 44: 45:
46: public static function isAvailable()
47: {
48: return extension_loaded('memcache');
49: }
50:
51:
52:
53: public function __construct($host = 'localhost', $port = 11211, $prefix = '', Nette\Context $context = NULL)
54: {
55: if (!self::isAvailable()) {
56: throw new \NotSupportedException("PHP extension 'memcache' is not loaded.");
57: }
58:
59: $this->prefix = $prefix;
60: $this->context = $context;
61: $this->memcache = new \Memcache;
62: Nette\Debug::tryError();
63: $this->memcache->connect($host, $port);
64: if (Nette\Debug::catchError($msg)) {
65: throw new \InvalidStateException($msg);
66: }
67: }
68:
69:
70:
71: 72: 73: 74: 75:
76: public function read($key)
77: {
78: $key = $this->prefix . $key;
79: $meta = $this->memcache->get($key);
80: if (!$meta) return NULL;
81:
82: 83: 84: 85: 86: 87: 88:
89: 90: if (!empty($meta[self::META_CALLBACKS]) && !Cache::checkCallbacks($meta[self::META_CALLBACKS])) {
91: $this->memcache->delete($key, 0);
92: return NULL;
93: }
94:
95: if (!empty($meta[self::META_DELTA])) {
96: $this->memcache->replace($key, $meta, 0, $meta[self::META_DELTA] + time());
97: }
98:
99: return $meta[self::META_DATA];
100: }
101:
102:
103:
104: 105: 106: 107: 108: 109: 110:
111: public function write($key, $data, array $dp)
112: {
113: if (isset($dp[Cache::ITEMS])) {
114: throw new \NotSupportedException('Dependent items are not supported by MemcachedStorage.');
115: }
116:
117: $meta = array(
118: self::META_DATA => $data,
119: );
120:
121: $expire = 0;
122: if (isset($dp[Cache::EXPIRE])) {
123: $expire = (int) $dp[Cache::EXPIRE];
124: if (!empty($dp[Cache::SLIDING])) {
125: $meta[self::META_DELTA] = $expire; 126: }
127: }
128:
129: if (isset($dp[Cache::CALLBACKS])) {
130: $meta[self::META_CALLBACKS] = $dp[Cache::CALLBACKS];
131: }
132:
133: if (isset($dp[Cache::TAGS]) || isset($dp[Cache::PRIORITY])) {
134: if (!$this->context) {
135: throw new \InvalidStateException('CacheJournal has not been provided.');
136: }
137: $this->getJournal()->write($this->prefix . $key, $dp);
138: }
139:
140: $this->memcache->set($this->prefix . $key, $meta, 0, $expire);
141: }
142:
143:
144:
145: 146: 147: 148: 149:
150: public function remove($key)
151: {
152: $this->memcache->delete($this->prefix . $key, 0);
153: }
154:
155:
156:
157: 158: 159: 160: 161:
162: public function clean(array $conds)
163: {
164: if (!empty($conds[Cache::ALL])) {
165: $this->memcache->flush();
166:
167: } elseif ($this->context) {
168: foreach ($this->getJournal()->clean($conds) as $entry) {
169: $this->memcache->delete($entry, 0);
170: }
171: }
172: }
173:
174:
175:
176: 177: 178:
179: protected function getJournal()
180: {
181: return $this->context->getService('Nette\\Caching\\ICacheJournal');
182: }
183:
184: }
185: