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