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