Completed
Push — master ( 462e40...0ae967 )
by Aimeos
01:32
created

Redis   B

Complexity

Total Complexity 39

Size/Duplication

Total Lines 266
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
wmc 39
lcom 1
cbo 3
dl 0
loc 266
rs 8.2857
c 0
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A get() 0 8 2
A __construct() 0 9 4
A clear() 0 4 1
A deleteMultiple() 0 8 2
A deleteByTags() 0 21 4
C getMultiple() 0 24 7
B getMultipleByTags() 0 26 6
A set() 0 18 4
D setMultiple() 0 31 9
1
<?php
2
3
/**
4
 * @license LGPLv3, http://www.gnu.org/licenses/lgpl.html
5
 * @copyright Metaways Infosystems GmbH, 2014
6
 * @copyright Aimeos (aimeos.org), 2015-2016
7
 * @package MW
8
 * @subpackage Cache
9
 */
10
11
12
namespace Aimeos\MW\Cache;
13
14
15
/**
16
 * Redis cache class.
17
 *
18
 * @package MW
19
 * @subpackage Cache
20
 */
21
class Redis
0 ignored issues
show
Bug introduced by
There is at least one abstract method in this class. Maybe declare it as abstract, or implement the remaining methods: deleteList, flush, getList, getListByTags, setList
Loading history...
22
	extends \Aimeos\MW\Cache\Base
23
	implements \Aimeos\MW\Cache\Iface
24
{
25
	private $client;
26
	private $siteid;
27
28
29
	/**
30
	 * Initializes the object instance.
31
	 *
32
	 * @param array $config Configuration for Predis client if instance should be created
33
	 * @param Predis\Client $client Predis client instance
34
	 */
35
	public function __construct( array $config, \Predis\Client $client )
36
	{
37
		$this->client = $client;
38
		$this->siteid = ( isset( $config['siteid'] ) ? $config['siteid'] . '-' : null );
39
40
		if( isset( $config['auth'] ) && !$this->client->auth( $config['auth'] ) ) {
41
			throw new \Aimeos\MW\Cache\Exception( 'Authentication failed for Redis' );
42
		}
43
	}
44
45
46
	/**
47
	 * Removes all entries of the site from the cache.
48
	 *
49
	 * @inheritDoc
50
	 *
51
	 * As Redis does only provider up to 20 different databases, this isn't enough
52
	 * to use one of them for each site. Alternatively, using the KEYS command
53
	 * to fetch all cache keys of a site and delete them afterwards can take very
54
	 * long for billions of keys. Therefore, flush() clears the cache entries of
55
	 * all sites.
56
	 *
57
	 * @throws \Aimeos\MW\Cache\Exception If the cache server doesn't respond
58
	 */
59
	public function clear()
60
	{
61
		$this->client->flushdb();
62
	}
63
64
65
	/**
66
	 * Removes the cache entries identified by the given keys.
67
	 *
68
	 * @inheritDoc
69
	 *
70
	 * @param array $keys List of key strings that identify the cache entries
71
	 * 	that should be removed
72
	 */
73
	public function deleteMultiple( $keys )
74
	{
75
		foreach( $keys as $idx => $key ) {
76
			$keys[$idx] = $this->siteid . $key;
77
		}
78
79
		$this->client->del( $keys );
80
	}
81
82
83
	/**
84
	 * Removes the cache entries identified by the given tags.
85
	 *
86
	 * @inheritDoc
87
	 *
88
	 * @param array $tags List of tag strings that are associated to one or more
89
	 * 	cache entries that should be removed
90
	 */
91
	public function deleteByTags( array $tags )
92
	{
93
		$result = $tagKeys = array();
94
		$pipe = $this->client->pipeline();
95
96
		foreach( $tags as $tag )
97
		{
98
			$tag = $this->siteid . 'tag:' . $tag;
99
			$pipe->smembers( $tag );
100
			$tagKeys[] = $tag;
101
		}
102
103
		foreach( $pipe->execute() as $keys )
104
		{
105
			foreach( $keys as $key ) {
106
				$result[$key] = null;
107
			}
108
		}
109
110
		$this->client->del( array_merge( array_keys( $result ), $tagKeys ) );
111
	}
112
113
114
	/**
115
	 * Returns the cached value for the given key.
116
	 *
117
	 * @inheritDoc
118
	 *
119
	 * @param string $key Path to the requested value like product/id/123
120
	 * @param mixed $default Value returned if requested key isn't found
121
	 * @return mixed Value associated to the requested key. If no value for the
122
	 *	key is found in the cache, the given default value is returned
123
	 */
124
	public function get( $key, $default = null )
125
	{
126
		if( ( $result = $this->client->get( $this->siteid . $key ) ) === null ) {
127
			return $default;
128
		}
129
130
		return $result;
131
	}
132
133
134
	/**
135
	 * Returns the cached values for the given cache keys if available.
136
	 *
137
	 * @inheritDoc
138
	 *
139
	 * @param iterable $keys List of key strings for the requested cache entries
140
	 * @param mixed $default Default value to return for keys that do not exist
141
	 * @return array Associative list of key/value pairs for the requested cache
142
	 * 	entries. If a cache entry doesn't exist, neither its key nor a value
143
	 * 	will be in the result list
144
	 */
145
	public function getMultiple( $keys, $default = null )
146
	{
147
		$result = $actkeys = array();
148
149
		foreach( $keys as $idx => $key ) {
150
			$actkeys[$idx] = $this->siteid . $key;
151
		}
152
153
		foreach( $this->client->mget( $actkeys ) as $idx => $value )
154
		{
155
			if( $value !== null && isset( $keys[$idx] ) ) {
156
				$result[ $keys[$idx] ] = $value;
157
			}
158
		}
159
160
		foreach( $keys as $key )
161
		{
162
			if( !isset( $result[$key] ) ) {
163
				$result[$key] = $default;
164
			}
165
		}
166
167
		return $result;
168
	}
169
170
171
	/**
172
	 * Returns the cached keys and values associated to the given tags if available.
173
	 *
174
	 * @inheritDoc
175
	 *
176
	 * @param array $tags List of tag strings associated to the requested cache entries
177
	 * @return array Associative list of key/value pairs for the requested cache
178
	 * 	entries. If a tag isn't associated to any cache entry, nothing is returned
179
	 * 	for that tag
180
	 */
181
	public function getMultipleByTags( array $tags )
182
	{
183
		$result = $actkeys = array();
184
		$len = strlen( $this->siteid );
185
		$pipe = $this->client->pipeline();
186
187
		foreach( $tags as $tag ) {
188
			$pipe->smembers( $this->siteid . 'tag:' . $tag );
189
		}
190
191
		foreach( $pipe->execute() as $keys )
192
		{
193
			foreach( $keys as $key ) {
194
				$actkeys[$key] = null;
195
			}
196
		}
197
198
		foreach( $this->client->mget( array_keys( $actkeys ) ) as $idx => $value )
199
		{
200
			if( isset( $keys[$idx] ) ) {
201
				$result[ substr( $keys[$idx], $len ) ] = $value;
202
			}
203
		}
204
205
		return $result;
206
	}
207
208
209
	/**
210
	 * Sets the value for the given key in the cache.
211
	 *
212
	 * @inheritDoc
213
	 *
214
	 * @param string $key Key string for the given value like product/id/123
215
	 * @param mixed $value Value string that should be stored for the given key
216
	 * @param int|string|null $expires Date/time string in "YYYY-MM-DD HH:mm:ss"
217
	 * 	format or as TTL value when the cache entry expires
218
	 * @param array $tags List of tag strings that should be assoicated to the
219
	 * 	given value in the cache
220
	 */
221
	public function set( $key, $value, $expires = null, array $tags = array() )
222
	{
223
		$key = $this->siteid . $key;
224
		$pipe = $this->client->pipeline();
225
		$pipe->set( $key, $value );
226
227
		foreach( $tags as $tag ) {
228
			$pipe->sadd( $this->siteid . 'tag:' . $tag, $key );
229
		}
230
231
		if( is_string( $expires ) ) {
232
			$pipe->expireat( $key, date_create( $expires )->getTimestamp() );
233
		} elseif( is_int( $expires ) ) {
234
			$pipe->expireat( $key, $expires );
235
		}
236
237
		$pipe->execute();
238
	}
239
240
241
	/**
242
	 * Adds or overwrites the given key/value pairs in the cache, which is much
243
	 * more efficient than setting them one by one using the set() method.
244
	 *
245
	 * @inheritDoc
246
	 *
247
	 * @param iterable $pairs Associative list of key/value pairs. Both must be
248
	 * 	a string
249
	 * @param array|int|string|null $expires Associative list of keys and datetime
250
	 *  string or integer TTL pairs.
251
	 * @param array $tags Associative list of key/tag or key/tags pairs that
252
	 *  should be associated to the values identified by their key. The value
253
	 *  associated to the key can either be a tag string or an array of tag strings
254
	 */
255
	public function setMultiple( $pairs, $expires = null, array $tags = array() )
256
	{
257
		$actpairs = array();
258
		$pipe = $this->client->pipeline();
259
260
		foreach( $pairs as $key => $value ) {
261
			$actpairs[ $this->siteid . $key ] = $value;
262
		}
263
264
		$pipe->mset( $actpairs );
265
266
		foreach( $pairs as $key => $value )
267
		{
268
			$expire = ( is_array( $expires ) && isset( $expires[$key] ) ? $expires[$key] : $expires );
269
270
			if( is_string( $expire ) ) {
271
				$pipe->expireat( $this->siteid . $key, date_create( $expire )->getTimestamp() );
272
			} elseif( is_int( $expire ) ) {
273
				$pipe->expire( $this->siteid . $key, $expire );
274
			}
275
		}
276
277
		foreach( $tags as $key => $tagList )
278
		{
279
			foreach( (array) $tagList as $tag ) {
280
				$pipe->sadd( $this->siteid . 'tag:' . $tag, $this->siteid . $key );
281
			}
282
		}
283
284
		$pipe->execute();
285
	}
286
}
287