Completed
Pull Request — master (#5)
by Michal
07:42
created

RedisProxy::__call()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 11
ccs 7
cts 7
cp 1
rs 9.4285
cc 2
eloc 8
nc 2
nop 2
crap 2
1
<?php
2
3
namespace RedisProxy;
4
5
use Exception;
6
use Predis\Client;
7
use Predis\Response\Status;
8
use Redis;
9
10
/**
11
 * @method mixed config(string $command, $argument = null)
12
 * @method int dbsize() Return the number of keys in the selected database
13
 * @method boolean set(string $key, string $value) Set the string value of a key
14
 * @method boolean setex(string $key, int $seconds, string $value) Set the value and expiration of a key
15
 * @method int ttl(string $key) Get the time to live for a key, returns TTL in seconds, -2 if the key does not exist, -1 if the key exists but has no associated expire
16
 * @method int pttl(string $key) Get the time to live for a key in milliseconds, returns TTL in miliseconds, -2 if the key does not exist, -1 if the key exists but has no associated expire
17
 * @method array keys(string $pattern) Find all keys matching the given pattern
18
 * @method int hset(string $key, string $field, string $value) Set the string value of a hash field
19
 * @method array hkeys(string $key) Get all fields in a hash (without values)
20
 * @method array hgetall(string $key) Get all fields and values in a hash
21
 * @method int hlen(string $key) Get the number of fields in a hash
22
 * @method array smembers(string $key) Get all the members in a set
23
 * @method int scard(string $key) Get the number of members in a set
24
 * @method int llen(string $key) Get the length of a list
25
 * @method array lrange(string $key, int $start, int $stop) Get a range of elements from a list
26
 * @method int zcard(string $key) Get the number of members in a sorted set
27
 * @method boolean flushall() Remove all keys from all databases
28
 * @method boolean flushdb() Remove all keys from the current database
29
 */
30
class RedisProxy
31
{
32
    const DRIVER_REDIS = 'redis';
33
34
    const DRIVER_PREDIS = 'predis';
35
36
    const TYPE_STRING = 'string';
37
38
    const TYPE_SET = 'set';
39
40
    const TYPE_HASH = 'hash';
41
42
    const TYPE_LIST = 'list';
43
44
    const TYPE_SORTED_SET = 'sorted_set';
45
46
    private $driver;
47
48
    private $host;
49
50
    private $port;
51
52
    private $database = 0;
53
54
    private $selectedDatabase = 0;
55
56
    private $timeout;
57
58
    private $supportedDrivers = [
59
        self::DRIVER_REDIS,
60
        self::DRIVER_PREDIS,
61
    ];
62
63
    private $driversOrder = [];
64
65
    private $redisTypeMap = [
66
        self::DRIVER_REDIS => [
67
            Redis::REDIS_STRING => self::TYPE_STRING,
68
            Redis::REDIS_SET => self::TYPE_SET,
69
            Redis::REDIS_HASH => self::TYPE_HASH,
70
            Redis::REDIS_LIST => self::TYPE_LIST,
71
            Redis::REDIS_ZSET => self::TYPE_SORTED_SET,
72
        ],
73
        self::DRIVER_PREDIS => [
74
            'string' => self::TYPE_STRING,
75
            'set' => self::TYPE_SET,
76
            'hash' => self::TYPE_HASH,
77
            'list' => self::TYPE_LIST,
78
            'zset' => self::TYPE_SORTED_SET,
79
        ],
80
    ];
81
82 244
    public function __construct($host, $port, $database = 0, $timeout = null)
83
    {
84 244
        $this->host = $host;
85 244
        $this->port = $port;
86 244
        $this->database = $database;
87 244
        $this->timeout = $timeout;
88 244
        $this->driversOrder = $this->supportedDrivers;
89 244
    }
90
91
    /**
92
     * Set driver priorities - default is 1. redis, 2. predis
93
     * @param array $driversOrder
94
     * @return RedisProxy
95
     * @throws RedisProxyException if some driver is not supported
96
     */
97 244
    public function setDriversOrder(array $driversOrder)
98
    {
99 244
        foreach ($driversOrder as $driver) {
100 242
            if (!in_array($driver, $this->supportedDrivers)) {
101 122
                throw new RedisProxyException('Driver "' . $driver . '" is not supported');
102
            }
103 121
        }
104 242
        $this->driversOrder = $driversOrder;
105 242
        return $this;
106
    }
107
108 242
    private function init()
109
    {
110 242
        $this->prepareDriver();
111 240
        $this->select($this->database);
112 240
    }
113
114 242
    private function prepareDriver()
115
    {
116 242
        if ($this->driver !== null) {
117 240
            return;
118
        }
119
120 242
        foreach ($this->driversOrder as $preferredDriver) {
121 240
            if ($preferredDriver === self::DRIVER_REDIS && extension_loaded('redis')) {
122 120
                $this->driver = new Redis();
123 120
                return;
124
            }
125 120
            if ($preferredDriver === self::DRIVER_PREDIS && class_exists('Predis\Client')) {
126 120
                $this->driver = new Client();
127 120
                return;
128
            }
129 1
        }
130 2
        throw new RedisProxyException('No driver available');
131
    }
132
133
    /**
134
     * @return string|null
135
     */
136 242
    public function actualDriver()
137
    {
138 242
        if ($this->driver instanceof Redis) {
139 120
            return self::DRIVER_REDIS;
140
        }
141 126
        if ($this->driver instanceof Client) {
142 120
            return self::DRIVER_PREDIS;
143
        }
144 10
        return null;
145
    }
146
147 240
    private function connect($host, $port, $timeout = null)
148
    {
149 240
        return $this->driver->connect($host, $port, $timeout);
150
    }
151
152 240
    private function isConnected()
153
    {
154 240
        return $this->driver->isConnected();
155
    }
156
157 242
    public function __call($name, $arguments)
158
    {
159 242
        $this->init();
160 240
        $name = strtolower($name);
161
        try {
162 240
            $result = call_user_func_array([$this->driver, $name], $arguments);
163 122
        } catch (Exception $e) {
164 4
            throw new RedisProxyException("Error for command '$name', use getPrevious() for more info", 1484162284, $e);
165
        }
166 240
        return $this->transformResult($result);
167
    }
168
169
    /**
170
     * @param int $database
171
     * @return boolean true on success
172
     * @throws RedisProxyException on failure
173
     */
174 240
    public function select($database)
175
    {
176 240
        $this->prepareDriver();
177 240
        if (!$this->isConnected()) {
178 240
            $this->connect($this->host, $this->port, $this->timeout);
179 120
        }
180 240
        if ($database == $this->selectedDatabase) {
181 240
            return true;
182
        }
183
        try {
184 12
            $result = $this->driver->select($database);
185 7
        } catch (Exception $e) {
186 2
            throw new RedisProxyException('Invalid DB index');
187
        }
188 10
        $result = $this->transformResult($result);
189 10
        if ($result === false) {
190 2
            throw new RedisProxyException('Invalid DB index');
191
        }
192 8
        $this->database = $database;
193 8
        $this->selectedDatabase = $database;
194 8
        return $result;
195
    }
196
197
    /**
198
     * @param string $key
199
     * @return string|null
200
     */
201 4
    public function type($key)
202
    {
203 4
        $this->init();
204 4
        $result = $this->driver->type($key);
205 4
        $result = $this->actualDriver() === self::DRIVER_PREDIS && $result instanceof Status ? $result->getPayload() : $result;
206 4
        return isset($this->redisTypeMap[$this->actualDriver()][$result]) ? $this->redisTypeMap[$this->actualDriver()][$result] : null;
207
    }
208
209
    /**
210
     * @param string|null $section
211
     * @return array
212
     */
213 8
    public function info($section = null)
214
    {
215 8
        $this->init();
216 8
        $section = $section ? strtolower($section) : $section;
217 8
        $result = $section === null ? $this->driver->info() : $this->driver->info($section);
218
219 8
        $databases = $section === null || $section === 'keyspace' ? $this->config('get', 'databases')['databases'] : null;
220 8
        $groupedResult = InfoHelper::createInfoArray($this, $result, $databases);
221 8
        if ($section === null) {
222 4
            return $groupedResult;
223
        }
224 8
        if (isset($groupedResult[$section])) {
225 4
            return $groupedResult[$section];
226
        }
227 4
        throw new RedisProxyException('Info section "' . $section . '" doesn\'t exist');
228
    }
229
230
    /**
231
     * Get the value of a key
232
     * @param string $key
233
     * @return string|null null if key not set
234
     */
235 72
    public function get($key)
236
    {
237 72
        $this->init();
238 72
        $result = $this->driver->get($key);
239 72
        return $this->convertFalseToNull($result);
240
    }
241
242
    /**
243
     * Set the string value of a key and return its old value
244
     * @param string $key
245
     * @param string $value
246
     * @return string|null null if key was not set before
247
     */
248 4
    public function getset($key, $value)
249
    {
250 4
        $this->init();
251 4
        $result = $this->driver->getset($key, $value);
252 4
        return $this->convertFalseToNull($result);
253
    }
254
255
    /**
256
     * Set a key's time to live in seconds
257
     * @param string $key
258
     * @param int $seconds
259
     * @return boolean true if the timeout was set, false if key does not exist or the timeout could not be set
260
     */
261 8
    public function expire($key, $seconds)
262
    {
263 8
        $this->init();
264 8
        $result = $this->driver->expire($key, $seconds);
265 8
        return (bool)$result;
266
    }
267
268
    /**
269
     * Set the expiration for a key as a UNIX timestamp
270
     * @param string $key
271
     * @param int $timestamp
272
     * @return boolean true if the timeout was set, false if key does not exist or the timeout could not be set
273
     */
274 4
    public function expireat($key, $timestamp)
275
    {
276 4
        $this->init();
277 4
        $result = $this->driver->expireat($key, $timestamp);
278 4
        return (bool)$result;
279
    }
280
281
    /**
282
     * Set the expiration for a key as a UNIX timestamp specified in milliseconds
283
     * @param string $key
284
     * @param int $timestamp
285
     * @return boolean true if the timeout was set, false if key does not exist or the timeout could not be set
286
     */
287 4
    public function pexpireat($key, $timestamp)
288
    {
289 4
        $this->init();
290 4
        $result = $this->driver->pexpireat($key, $timestamp);
291 4
        return (bool)$result;
292
    }
293
294
    /**
295
     * Set the value and expiration in milliseconds of a key
296
     * @param string $key
297
     * @param int $miliseconds
298
     * @param string $value
299
     * @return boolean
300
     */
301 4
    public function psetex($key, $miliseconds, $value)
302
    {
303 4
        $this->init();
304 4
        $result = $this->driver->psetex($key, $miliseconds, $value);
305 4
        if ($result == '+OK') {
306 2
            return true;
307
        }
308 2
        return $this->transformResult($result);
309
    }
310
311
    /**
312
     * Set the value of a key, only if the key does not exist
313
     * @param string $key
314
     * @param string $value
315
     * @return boolean true if the key was set, false if the key was not set
316
     */
317 4
    public function setnx($key, $value)
318
    {
319 4
        $this->init();
320 4
        $result = $this->driver->setnx($key, $value);
321 4
        return (bool)$result;
322
    }
323
324
    /**
325
     * Delete a key(s)
326
     * @param array $keys
327
     * @return int number of deleted keys
328
     */
329 28
    public function del(...$keys)
330
    {
331 28
        $this->prepareArguments('del', ...$keys);
332 20
        $this->init();
333 20
        return $this->driver->del(...$keys);
334
    }
335
336
    /**
337
     * Delete a key(s)
338
     * @param array $keys
339
     * @return int number of deleted keys
340
     */
341 12
    public function delete(...$keys)
342
    {
343 12
        return $this->del(...$keys);
344
    }
345
346
    /**
347
     * Increment the integer value of a key by one
348
     * @param string $key
349
     * @return integer
350
     */
351 4
    public function incr($key)
352
    {
353 4
        $this->init();
354 4
        return $this->driver->incr($key);
355
    }
356
357
    /**
358
     * Increment the integer value of a key by the given amount
359
     * @param string $key
360
     * @param integer $increment
361
     * @return integer
362
     */
363 4
    public function incrby($key, $increment = 1)
364
    {
365 4
        $this->init();
366 4
        return $this->driver->incrby($key, (int)$increment);
367
    }
368
369
    /**
370
     * Increment the float value of a key by the given amount
371
     * @param string $key
372
     * @param float $increment
373
     * @return float
374
     */
375 8
    public function incrbyfloat($key, $increment = 1)
376
    {
377 8
        $this->init();
378 8
        return $this->driver->incrbyfloat($key, $increment);
379
    }
380
381
    /**
382
     * Decrement the integer value of a key by one
383
     * @param string $key
384
     * @return integer
385
     */
386 4
    public function decr($key)
387
    {
388 4
        $this->init();
389 4
        return $this->driver->decr($key);
390
    }
391
392
    /**
393
     * Decrement the integer value of a key by the given number
394
     * @param string $key
395
     * @param integer $decrement
396
     * @return integer
397
     */
398 4
    public function decrby($key, $decrement = 1)
399
    {
400 4
        $this->init();
401 4
        return $this->driver->decrby($key, (int)$decrement);
402
    }
403
404
    /**
405
     * Decrement the float value of a key by the given amount
406
     * @param string $key
407
     * @param float $decrement
408
     * @return float
409
     */
410 4
    public function decrbyfloat($key, $decrement = 1)
411
    {
412 4
        return $this->incrbyfloat($key, (-1) * $decrement);
413
    }
414
415
    /**
416
     * Set multiple values to multiple keys
417
     * @param array $dictionary
418
     * @return boolean true on success
419
     * @throws RedisProxyException if number of arguments is wrong
420
     */
421 12 View Code Duplication
    public function mset(...$dictionary)
422
    {
423 12
        $this->init();
424 12
        if (is_array($dictionary[0])) {
425 8
            $result = $this->driver->mset(...$dictionary);
426 8
            return $this->transformResult($result);
427
        }
428 8
        $dictionary = $this->prepareKeyValue($dictionary, 'mset');
429 4
        $result = $this->driver->mset($dictionary);
430 4
        return $this->transformResult($result);
431
    }
432
433
    /**
434
     * Multi get
435
     * @param array $keys
436
     * @return array Returns the values for all specified keys. For every key that does not hold a string value or does not exist, null is returned
437
     */
438 4
    public function mget(...$keys)
439
    {
440 4
        $keys = array_unique($this->prepareArguments('mget', ...$keys));
441 4
        $this->init();
442 4
        $values = [];
443 4
        foreach ($this->driver->mget($keys) as $value) {
444 4
            $values[] = $this->convertFalseToNull($value);
445 2
        }
446 4
        return array_combine($keys, $values);
447
    }
448
449
    /**
450
     * Incrementally iterate the keys space
451
     * @param mixed $iterator iterator / cursor, use $iterator = null for start scanning, when $iterator is changed to 0 or '0', scanning is finished
452
     * @param string $pattern pattern for keys, use * as wild card
453
     * @param int $count
454
     * @return array|boolean|null list of found keys, returns null if $iterator is 0 or '0'
455
     */
456 4 View Code Duplication
    public function scan(&$iterator, $pattern = null, $count = null)
457
    {
458 4
        if ((string)$iterator === '0') {
459 4
            return null;
460
        }
461 4
        $this->init();
462 4
        if ($this->actualDriver() === self::DRIVER_PREDIS) {
463 2
            $returned = $this->driver->scan($iterator, ['match' => $pattern, 'count' => $count]);
464 2
            $iterator = $returned[0];
465 2
            return $returned[1];
466
        }
467 2
        return $this->driver->scan($iterator, $pattern, $count);
468
    }
469
470
    /**
471
     * Get the value of a hash field
472
     * @param string $key
473
     * @param string $field
474
     * @return string|null null if hash field is not set
475
     */
476 16
    public function hget($key, $field)
477
    {
478 16
        $this->init();
479 16
        $result = $this->driver->hget($key, $field);
480 16
        return $this->convertFalseToNull($result);
481
    }
482
483
    /**
484
     * Delete one or more hash fields, returns number of deleted fields
485
     * @param array $key
486
     * @param array $fields
487
     * @return int
488
     */
489 8
    public function hdel($key, ...$fields)
490
    {
491 8
        $fields = $this->prepareArguments('hdel', ...$fields);
492 8
        $this->init();
493 8
        return $this->driver->hdel($key, ...$fields);
494
    }
495
496
    /**
497
     * Increment the integer value of hash field by given number
498
     * @param string $key
499
     * @param string $field
500
     * @param int $increment
501
     * @return int
502
     */
503 4
    public function hincrby($key, $field, $increment = 1)
504
    {
505 4
        $this->init();
506 4
        return $this->driver->hincrby($key, $field, (int)$increment);
507
    }
508
509
    /**
510
     * Increment the float value of hash field by given amount
511
     * @param string $key
512
     * @param string $field
513
     * @param float $increment
514
     * @return float
515
     */
516 4
    public function hincrbyfloat($key, $field, $increment = 1)
517
    {
518 4
        $this->init();
519 4
        return $this->driver->hincrbyfloat($key, $field, $increment);
520
    }
521
522
    /**
523
     * Set multiple values to multiple hash fields
524
     * @param string $key
525
     * @param array $dictionary
526
     * @return boolean true on success
527
     * @throws RedisProxyException if number of arguments is wrong
528
     */
529 12 View Code Duplication
    public function hmset($key, ...$dictionary)
530
    {
531 12
        $this->init();
532 12
        if (is_array($dictionary[0])) {
533 8
            $result = $this->driver->hmset($key, ...$dictionary);
534 8
            return $this->transformResult($result);
535
        }
536 8
        $dictionary = $this->prepareKeyValue($dictionary, 'hmset');
537 4
        $result = $this->driver->hmset($key, $dictionary);
538 4
        return $this->transformResult($result);
539
    }
540
541
    /**
542
     * Multi hash get
543
     * @param string $key
544
     * @param array $fields
545
     * @return array Returns the values for all specified fields. For every field that does not hold a string value or does not exist, null is returned
546
     */
547 4
    public function hmget($key, ...$fields)
548
    {
549 4
        $fields = array_unique($this->prepareArguments('hmget', ...$fields));
550 4
        $this->init();
551 4
        $values = [];
552 4
        foreach ($this->driver->hmget($key, $fields) as $value) {
553 4
            $values[] = $this->convertFalseToNull($value);
554 2
        }
555 4
        return array_combine($fields, $values);
556
    }
557
558
    /**
559
     * Incrementally iterate hash fields and associated values
560
     * @param string $key
561
     * @param mixed $iterator iterator / cursor, use $iterator = null for start scanning, when $iterator is changed to 0 or '0', scanning is finished
562
     * @param string $pattern pattern for fields, use * as wild card
563
     * @param int $count
564
     * @return array|boolean|null list of found fields with associated values, returns null if $iterator is 0 or '0'
565
     */
566 4 View Code Duplication
    public function hscan($key, &$iterator, $pattern = null, $count = null)
567
    {
568 4
        if ((string)$iterator === '0') {
569 4
            return null;
570
        }
571 4
        $this->init();
572 4
        if ($this->actualDriver() === self::DRIVER_PREDIS) {
573 2
            $returned = $this->driver->hscan($key, $iterator, ['match' => $pattern, 'count' => $count]);
574 2
            $iterator = $returned[0];
575 2
            return $returned[1];
576
        }
577 2
        return $this->driver->hscan($key, $iterator, $pattern, $count);
578
    }
579
580
    /**
581
     * Add one or more members to a set
582
     * @param string $key
583
     * @param array $members
584
     * @return int number of new members added to set
585
     */
586 16
    public function sadd($key, ...$members)
587
    {
588 16
        $members = $this->prepareArguments('sadd', ...$members);
589 16
        $this->init();
590 16
        return $this->driver->sadd($key, ...$members);
591
    }
592
593
    /**
594
     * Remove and return one or multiple random members from a set
595
     * @param string $key
596
     * @param int $count number of members
597
     * @return mixed string if $count is null or 1 and $key exists, array if $count > 1 and $key exists, null if $key doesn't exist
598
     */
599 4
    public function spop($key, $count = 1)
600
    {
601 4
        $this->init();
602 4
        if ($count == 1 || $count === null) {
603 4
            $result = $this->driver->spop($key);
604 4
            return $this->convertFalseToNull($result);
605
        }
606
607 4
        $members = [];
608 4
        for ($i = 0; $i < $count; ++$i) {
609 4
            $member = $this->driver->spop($key);
610 4
            if (!$member) {
611 4
                break;
612
            }
613 4
            $members[] = $member;
614 2
        }
615 4
        return empty($members) ? null : $members;
616
    }
617
618
    /**
619
     * Incrementally iterate Set elements
620
     * @param string $key
621
     * @param mixed $iterator iterator / cursor, use $iterator = null for start scanning, when $iterator is changed to 0 or '0', scanning is finished
622
     * @param string $pattern pattern for member's values, use * as wild card
623
     * @param int $count
624
     * @return array|boolean|null list of found members, returns null if $iterator is 0 or '0'
625
     */
626 4 View Code Duplication
    public function sscan($key, &$iterator, $pattern = null, $count = null)
627
    {
628 4
        if ((string)$iterator === '0') {
629 4
            return null;
630
        }
631 4
        $this->init();
632 4
        if ($this->actualDriver() === self::DRIVER_PREDIS) {
633 2
            $returned = $this->driver->sscan($key, $iterator, ['match' => $pattern, 'count' => $count]);
634 2
            $iterator = $returned[0];
635 2
            return $returned[1];
636
        }
637 2
        return $this->driver->sscan($key, $iterator, $pattern, $count);
638
    }
639
640
    /**
641
     * Prepend one or multiple values to a list
642
     * @param string $key
643
     * @param array $elements
644
     * @return int the length of the list after the push operations
645
     */
646 28
    public function lpush($key, ...$elements)
647
    {
648 28
        $elements = $this->prepareArguments('lpush', ...$elements);
649 28
        $this->init();
650 28
        return $this->driver->lpush($key, ...$elements);
651
    }
652
653
    /**
654
     * Append one or multiple values to a list
655
     * @param string $key
656
     * @param array $elements
657
     * @return int the length of the list after the push operations
658
     */
659 12
    public function rpush($key, ...$elements)
660
    {
661 12
        $elements = $this->prepareArguments('rpush', ...$elements);
662 12
        $this->init();
663 12
        return $this->driver->rpush($key, ...$elements);
664
    }
665
666
    /**
667
     * Remove and get the first element in a list
668
     * @param string $key
669
     * @return string|null
670
     */
671 4
    public function lpop($key)
672
    {
673 4
        $this->init();
674 4
        $result = $this->driver->lpop($key);
675 4
        return $this->convertFalseToNull($result);
676
    }
677
678
    /**
679
     * Remove and get the last element in a list
680
     * @param string $key
681
     * @return string|null
682
     */
683 4
    public function rpop($key)
684
    {
685 4
        $this->init();
686 4
        $result = $this->driver->rpop($key);
687 4
        return $this->convertFalseToNull($result);
688
    }
689
690
    /**
691
     * Get an element from a list by its index
692
     * @param string $key
693
     * @param int $index zero-based, so 0 means the first element, 1 the second element and so on. -1 means the last element, -2 means the penultimate and so forth
694
     * @return string|null
695
     */
696 12
    public function lindex($key, $index)
697
    {
698 12
        $this->init();
699 12
        $result = $this->driver->lindex($key, $index);
700 12
        return $this->convertFalseToNull($result);
701
    }
702
703
    /**
704
     * Add one or more members to a sorted set, or update its score if it already exists
705
     * @param string $key
706
     * @param array $dictionary (score1, member1[, score2, member2]) or associative array: [member1 => score1, member2 => score2]
707
     * @return int
708
     */
709 20
    public function zadd($key, ...$dictionary)
710
    {
711 20
        $this->init();
712 20
        if (is_array($dictionary[0])) {
713 12
            $return = 0;
714 12
            foreach ($dictionary[0] as $member => $score) {
715 12
                $res = $this->zadd($key, $score, $member);
716 12
                $return += $res;
717 6
            }
718 12
            return $return;
719
        }
720 20
        return $this->driver->zadd($key, ...$dictionary);
721
    }
722
723
    /**
724
     * Return a range of members in a sorted set, by index
725
     * @param string $key
726
     * @param int $start
727
     * @param int $stop
728
     * @param boolean $withscores
729
     * @return array
730
     */
731 4 View Code Duplication
    public function zrange($key, $start, $stop, $withscores = false)
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
732
    {
733 4
        $this->init();
734 4
        if ($this->actualDriver() === self::DRIVER_PREDIS) {
735 2
            return $this->driver->zrange($key, $start, $stop, ['WITHSCORES' => $withscores]);
736
        }
737 2
        return $this->driver->zrange($key, $start, $stop, $withscores);
738
    }
739
740
    /**
741
     * Return a range of members in a sorted set, by index, with scores ordered from high to low
742
     * @param string $key
743
     * @param int $start
744
     * @param int $stop
745
     * @param boolean $withscores
746
     * @return array
747
     */
748 4 View Code Duplication
    public function zrevrange($key, $start, $stop, $withscores = false)
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
749
    {
750 4
        $this->init();
751 4
        if ($this->actualDriver() === self::DRIVER_PREDIS) {
752 2
            return $this->driver->zrevrange($key, $start, $stop, ['WITHSCORES' => $withscores]);
753
        }
754 2
        return $this->driver->zrevrange($key, $start, $stop, $withscores);
755
    }
756
757
    /**
758
     * Returns null instead of false for Redis driver
759
     * @param mixed $result
760
     * @return mixed
761
     */
762 112
    private function convertFalseToNull($result)
763
    {
764 112
        return $this->actualDriver() === self::DRIVER_REDIS && $result === false ? null : $result;
765
    }
766
767
    /**
768
     * Transforms Predis result Payload to boolean
769
     * @param mixed $result
770
     * @return mixed
771
     */
772 240
    private function transformResult($result)
773
    {
774 240
        if ($this->actualDriver() === self::DRIVER_PREDIS && $result instanceof Status) {
775 120
            $result = $result->getPayload() === 'OK';
776 60
        }
777 240
        return $result;
778
    }
779
780
    /**
781
     * Create array from input array - odd keys are used as keys, even keys are used as values
782
     * @param array $dictionary
783
     * @param string $command
784
     * @return array
785
     * @throws RedisProxyException if number of keys is not the same as number of values
786
     */
787 16
    private function prepareKeyValue(array $dictionary, $command)
788
    {
789
        $keys = array_values(array_filter($dictionary, function ($key) {
790 16
            return $key % 2 == 0;
791 16
        }, ARRAY_FILTER_USE_KEY));
792 16
        $values = array_values(array_filter($dictionary, function ($key) {
793 16
            return $key % 2 == 1;
794 16
        }, ARRAY_FILTER_USE_KEY));
795
796 16
        if (count($keys) != count($values)) {
797 8
            throw new RedisProxyException("Wrong number of arguments for $command command");
798
        }
799 8
        return array_combine($keys, $values);
800
    }
801
802 84
    private function prepareArguments($command, ...$params)
803
    {
804 84
        if (!isset($params[0])) {
805 8
            throw new RedisProxyException("Wrong number of arguments for $command command");
806
        }
807 76
        if (is_array($params[0])) {
808 32
            $params = $params[0];
809 16
        }
810 76
        return $params;
811
    }
812
}
813