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