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