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