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