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: if ($this->memcache->addServer($host, $port, TRUE, 1, $timeout) === FALSE) {
72: $error = error_get_last();
73: throw new Nette\InvalidStateException("Memcache::addServer(): $error[message].");
74: }
75: }
76:
77:
78:
79: 80: 81:
82: public function getConnection()
83: {
84: return $this->memcache;
85: }
86:
87:
88:
89: 90: 91: 92: 93:
94: public function read($key)
95: {
96: $key = $this->prefix . $key;
97: $meta = $this->memcache->get($key);
98: if (!$meta) {
99: return NULL;
100: }
101:
102:
103:
104:
105:
106:
107:
108:
109:
110: if (!empty($meta[self::META_CALLBACKS]) && !Cache::checkCallbacks($meta[self::META_CALLBACKS])) {
111: $this->memcache->delete($key, 0);
112: return NULL;
113: }
114:
115: if (!empty($meta[self::META_DELTA])) {
116: $this->memcache->replace($key, $meta, 0, $meta[self::META_DELTA] + time());
117: }
118:
119: return $meta[self::META_DATA];
120: }
121:
122:
123:
124: 125: 126: 127: 128:
129: public function lock($key)
130: {
131: }
132:
133:
134:
135: 136: 137: 138: 139: 140: 141:
142: public function write($key, $data, array $dp)
143: {
144: if (isset($dp[Cache::ITEMS])) {
145: throw new Nette\NotSupportedException('Dependent items are not supported by MemcachedStorage.');
146: }
147:
148: $key = $this->prefix . $key;
149: $meta = array(
150: self::META_DATA => $data,
151: );
152:
153: $expire = 0;
154: if (isset($dp[Cache::EXPIRATION])) {
155: $expire = (int) $dp[Cache::EXPIRATION];
156: if (!empty($dp[Cache::SLIDING])) {
157: $meta[self::META_DELTA] = $expire;
158: }
159: }
160:
161: if (isset($dp[Cache::CALLBACKS])) {
162: $meta[self::META_CALLBACKS] = $dp[Cache::CALLBACKS];
163: }
164:
165: if (isset($dp[Cache::TAGS]) || isset($dp[Cache::PRIORITY])) {
166: if (!$this->journal) {
167: throw new Nette\InvalidStateException('CacheJournal has not been provided.');
168: }
169: $this->journal->write($key, $dp);
170: }
171:
172: $this->memcache->set($key, $meta, 0, $expire);
173: }
174:
175:
176:
177: 178: 179: 180: 181:
182: public function remove($key)
183: {
184: $this->memcache->delete($this->prefix . $key, 0);
185: }
186:
187:
188:
189: 190: 191: 192: 193:
194: public function clean(array $conditions)
195: {
196: if (!empty($conditions[Cache::ALL])) {
197: $this->memcache->flush();
198:
199: } elseif ($this->journal) {
200: foreach ($this->journal->clean($conditions) as $entry) {
201: $this->memcache->delete($entry, 0);
202: }
203: }
204: }
205:
206: }
207: