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 (!self::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: Nette\Diagnostics\Debugger::tryError();
63: $this->memcache->connect($host, $port);
64: if (Nette\Diagnostics\Debugger::catchError($e)) {
65: throw new Nette\InvalidStateException('Memcache::connect(): ' . $e->getMessage(), 0, $e);
66: }
67: }
68:
69:
70:
71: 72: 73: 74: 75:
76: public function read($key)
77: {
78: $key = $this->prefix . $key;
79: $meta = $this->memcache->get($key);
80: if (!$meta) {
81: return NULL;
82: }
83:
84:
85:
86:
87:
88:
89:
90:
91:
92: if (!empty($meta[self::META_CALLBACKS]) && !Cache::checkCallbacks($meta[self::META_CALLBACKS])) {
93: $this->memcache->delete($key, 0);
94: return NULL;
95: }
96:
97: if (!empty($meta[self::META_DELTA])) {
98: $this->memcache->replace($key, $meta, 0, $meta[self::META_DELTA] + time());
99: }
100:
101: return $meta[self::META_DATA];
102: }
103:
104:
105:
106: 107: 108: 109: 110: 111: 112:
113: public function write($key, $data, array $dp)
114: {
115: if (isset($dp[Cache::ITEMS])) {
116: throw new Nette\NotSupportedException('Dependent items are not supported by MemcachedStorage.');
117: }
118:
119: $key = $this->prefix . $key;
120: $meta = array(
121: self::META_DATA => $data,
122: );
123:
124: $expire = 0;
125: if (isset($dp[Cache::EXPIRATION])) {
126: $expire = (int) $dp[Cache::EXPIRATION];
127: if (!empty($dp[Cache::SLIDING])) {
128: $meta[self::META_DELTA] = $expire;
129: }
130: }
131:
132: if (isset($dp[Cache::CALLBACKS])) {
133: $meta[self::META_CALLBACKS] = $dp[Cache::CALLBACKS];
134: }
135:
136: if (isset($dp[Cache::TAGS]) || isset($dp[Cache::PRIORITY])) {
137: if (!$this->journal) {
138: throw new Nette\InvalidStateException('CacheJournal has not been provided.');
139: }
140: $this->journal->write($key, $dp);
141: }
142:
143: $this->memcache->set($key, $meta, 0, $expire);
144: }
145:
146:
147:
148: 149: 150: 151: 152:
153: public function remove($key)
154: {
155: $this->memcache->delete($this->prefix . $key, 0);
156: }
157:
158:
159:
160: 161: 162: 163: 164:
165: public function clean(array $conds)
166: {
167: if (!empty($conds[Cache::ALL])) {
168: $this->memcache->flush();
169:
170: } elseif ($this->journal) {
171: foreach ($this->journal->clean($conds) as $entry) {
172: $this->memcache->delete($entry, 0);
173: }
174: }
175: }
176:
177: }
178: