mirror of
https://github.com/predis/predis.git
synced 2026-08-19 21:13:47 +00:00
Compare commits
60 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c5b60884e8 | |||
| 836ab07d40 | |||
| 2bfc8a9316 | |||
| d21576669d | |||
| 65fe24e346 | |||
| fbf270156f | |||
| 24630fbd5b | |||
| bded73f516 | |||
| 6a3f4a4c08 | |||
| 47896f1be7 | |||
| 586b039289 | |||
| d1acca607e | |||
| 721c829042 | |||
| b8cc7c643a | |||
| b47aa7ad3a | |||
| bb65b31580 | |||
| e540ca062b | |||
| 9c543ef5b1 | |||
| 83fb0020a1 | |||
| 4a77aea9ef | |||
| 72bc11eb63 | |||
| f26fd899f9 | |||
| 65447807ed | |||
| 5418cd5813 | |||
| bc5892e260 | |||
| 7c0cc7bdbe | |||
| 87ecd7bde2 | |||
| f9e77a0562 | |||
| d2b05ff58a | |||
| e24ecbbf90 | |||
| 9f3bdd5616 | |||
| 57a24413c2 | |||
| 0e6126ba9d | |||
| 7904fed6da | |||
| cfd6f030bc | |||
| 35d18d739a | |||
| 573c54ac4c | |||
| 169604bf74 | |||
| 94bd54b2af | |||
| bdebad7d62 | |||
| 1a411d2ad7 | |||
| 1400689df8 | |||
| ff59f74581 | |||
| 1a0eb7ee85 | |||
| bb6c1a7b6d | |||
| 42c33a406f | |||
| 7ad74217c2 | |||
| 72d7675563 | |||
| 8b5fa92856 | |||
| 076a62e3d3 | |||
| 85dc1752b7 | |||
| 7683215023 | |||
| dd4ddf6504 | |||
| 6468e6cc2e | |||
| 12f6d30502 | |||
| a602fc7425 | |||
| 4ec74cc5fe | |||
| 78fd4cb998 | |||
| 2a8dd6a7f1 | |||
| 7d7b3416a8 |
+1
-1
@@ -8,9 +8,9 @@ indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.php]
|
||||
trim_trailing_whitespace = true
|
||||
max_line_length = 120
|
||||
|
||||
[*.{md,yml}]
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
name-template: 'v$NEXT_MINOR_VERSION'
|
||||
tag-template: 'v$NEXT_MINOR_VERSION'
|
||||
change-template: '- $TITLE (#$NUMBER)'
|
||||
|
||||
autolabeler:
|
||||
- label: 'maintenance'
|
||||
files:
|
||||
- '*.md'
|
||||
- '.github/*'
|
||||
- label: 'bug'
|
||||
branch:
|
||||
- '/bug-.+'
|
||||
- label: 'maintenance'
|
||||
branch:
|
||||
- '/maintenance-.+'
|
||||
- label: 'feature'
|
||||
branch:
|
||||
- '/feature-.+'
|
||||
|
||||
categories:
|
||||
- title: 'Breaking Changes'
|
||||
labels:
|
||||
- 'breakingchange'
|
||||
- title: 'Experimental Features'
|
||||
labels:
|
||||
- 'experimental'
|
||||
- title: 'New Features'
|
||||
labels:
|
||||
- 'feature'
|
||||
- 'enhancement'
|
||||
- title: 'Bug Fixes'
|
||||
labels:
|
||||
- 'fix'
|
||||
- 'bugfix'
|
||||
- 'bug'
|
||||
- 'BUG'
|
||||
- title: 'Maintenance'
|
||||
label: 'maintenance'
|
||||
|
||||
exclude-labels:
|
||||
- 'skip-changelog'
|
||||
|
||||
template: |
|
||||
$CHANGES
|
||||
|
||||
## Contributors
|
||||
We'd like to thank all the contributors who worked on this release!
|
||||
|
||||
$CONTRIBUTORS
|
||||
@@ -0,0 +1,21 @@
|
||||
name: Release Drafter
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
|
||||
update_release_draft:
|
||||
|
||||
name: Update release draft
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
||||
- uses: release-drafter/release-drafter@v5
|
||||
with:
|
||||
config-name: release-drafter-config.yml
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
+43
-31
@@ -7,46 +7,58 @@ on:
|
||||
jobs:
|
||||
|
||||
predis:
|
||||
name: PHP ${{ matrix.php-versions }} (Redis ${{ matrix.redis-versions }})
|
||||
name: PHP ${{ matrix.php }} (Redis ${{ matrix.redis }})
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
services:
|
||||
redis:
|
||||
image: redis:${{ matrix.redis-versions }}
|
||||
ports:
|
||||
- 6379:6379
|
||||
options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php-versions: ['7.2', '7.3', '7.4', '8.0', '8.1']
|
||||
redis-versions: ['3', '4', '5', '6', '7']
|
||||
php:
|
||||
- '7.2'
|
||||
- '7.3'
|
||||
- '7.4'
|
||||
- '8.0'
|
||||
- '8.1'
|
||||
- '8.2'
|
||||
redis:
|
||||
- 3
|
||||
- 4
|
||||
- 5
|
||||
- 6
|
||||
- 7
|
||||
|
||||
services:
|
||||
redis:
|
||||
image: redis:${{ matrix.redis }}
|
||||
options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
|
||||
ports:
|
||||
- 6379:6379
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Setup PHP with Composer and extensions
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
uses: shivammathur/setup-php@v2
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Get Composer cache directory
|
||||
id: composercache
|
||||
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
|
||||
- name: Setup PHP with Composer and extensions
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
uses: shivammathur/setup-php@v2
|
||||
|
||||
- name: Cache Composer dependencies
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ steps.composercache.outputs.dir }}
|
||||
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
|
||||
restore-keys: ${{ runner.os }}-composer-
|
||||
- name: Get Composer cache directory
|
||||
id: composer-cache
|
||||
run: echo "directory=$(composer config cache-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Install Composer dependencies
|
||||
env:
|
||||
PHP_VERSION: ${{ matrix.php-versions }}
|
||||
run: composer install --no-progress --prefer-dist --optimize-autoloader $(if [ "$PHP_VERSION" == "8.0" ]; then echo "--ignore-platform-reqs"; fi;)
|
||||
- name: Cache Composer dependencies
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.directory }}
|
||||
key: tests-php-${{ matrix.php }}-composer-${{ hashFiles('**/composer.lock') }}
|
||||
restore-keys: tests-php-${{ matrix.php }}-composer
|
||||
|
||||
- name: Test with PHPUnit
|
||||
run: vendor/bin/phpunit
|
||||
- name: Install Composer dependencies
|
||||
env:
|
||||
PHP_VERSION: ${{ matrix.php }}
|
||||
run: composer install --ansi --no-progress --prefer-dist $(if [ "$PHP_VERSION" == "8.0" ]; then echo "--ignore-platform-reqs"; fi;)
|
||||
|
||||
- name: Run PHPUnit tests
|
||||
run: vendor/bin/phpunit
|
||||
|
||||
+60
-2
@@ -1,5 +1,63 @@
|
||||
## Changelog
|
||||
|
||||
## v2.1.1 (2023-01-17)
|
||||
|
||||
## Bug Fixes
|
||||
- Fix `@template` in `Predis\Client` (#1017)
|
||||
- Fix support options array in `ZINTERSTORE` and `ZUNIONSTORE` (#1018)
|
||||
|
||||
## v2.1.0 (2023-01-16)
|
||||
|
||||
## New Features
|
||||
|
||||
- Implemented `GETEX` command (#872)
|
||||
- Implemented `GETDEL` command (#869)
|
||||
- Implemented `COPY` command (#866)
|
||||
- Implemented `FAILOVER` command (#875)
|
||||
- Implemented `LMOVE` command (#863)
|
||||
- Implemented `LMPOP` command (#1013)
|
||||
- Implemented `HRANDFIELD` command (#870)
|
||||
- Implemented `SMISMEMBER` command (#871)
|
||||
- Implemented `ZMPOP` command (#831)
|
||||
- Implemented `BLMOVE` command (#865)
|
||||
- Implemented `BLMPOP` command (#1015)
|
||||
- Implemented `BZMPOP` command (#833)
|
||||
- Implemented `BZPOPMIN` command (#862)
|
||||
- Implemented `BZPOPMAX` command (#864)
|
||||
- Implemented `ZUNION` command (#860)
|
||||
- Implemented `ZINTER` command (#859)
|
||||
- Implemented `ZINTERCARD` command (#861)
|
||||
- Implemented `ZRANGESTORE` command (#829)
|
||||
- Implemented `ZDIFFSTORE` command (#828)
|
||||
- Implemented `ZDIFF` command (#826)
|
||||
- Implemented `ZRANDMEMBER` command (#825)
|
||||
- Implemented `ZMSCORE` (#823)
|
||||
- Implemented `GEOSEARCH` command (#867)
|
||||
- Implemented `GEOSEARCHSTORE` command (#873)
|
||||
|
||||
## Bug Fixes
|
||||
- Added annotations to suppress PHP 8.1 return type deprecation warning (#810)
|
||||
|
||||
## Maintenance
|
||||
- Added mixin annotations for traits (#835)
|
||||
|
||||
## v2.0.3 (2022-10-11)
|
||||
|
||||
- Improved PHP 8.2 support
|
||||
- Call `is_resource()` before reading/writing
|
||||
- Added partial support for Redis Stream commands
|
||||
- Fixed Sentinel authentication issue
|
||||
|
||||
## v2.0.2 (2022-09-06)
|
||||
|
||||
- Fixed PHP 8.2 deprecation notice: Use of "static" in callables
|
||||
|
||||
## v2.0.1 (2022-09-04)
|
||||
|
||||
- Added retry interval to `RedisCluster` with a default of `10ms`
|
||||
- Avoid PHP 8.2 warning in `Connection\Parameters`
|
||||
- Fixed Sentinel reconnect issue in long-running PHP processes
|
||||
|
||||
## v2.0.0 (2022-06-08)
|
||||
|
||||
- Dropped support for PHP 7.1 and older
|
||||
@@ -109,7 +167,7 @@
|
||||
|
||||
- Support Pub/Sub and Pipelines when using replication
|
||||
|
||||
- The class `Predis\Transaction\AbortedMultiExecException` now uses the correct
|
||||
- The class `Predis\Transaction\AbortedMultiExecException` now uses the correct
|
||||
default types for the `$code` (integer) parameter.
|
||||
|
||||
- __FIX__: using `strval` in `getScanOptions()` method, part of
|
||||
@@ -117,7 +175,7 @@
|
||||
string value of `$this->match` and not passing `null` to `strlen()` function.
|
||||
|
||||
- __FIX__: the value returned from `getArgument()` in `isReadOperation()` method,
|
||||
part of `Predis\Replication\ReplicationStrategy` class, is checked to not pass
|
||||
part of `Predis\Replication\ReplicationStrategy` class, is checked to not pass
|
||||
`null` to `sha1` function.
|
||||
|
||||
- __FIX__: the value returned from `getArgument()` in `parseResponse()`method,
|
||||
|
||||
@@ -35,6 +35,10 @@ This library can be found on [Packagist](http://packagist.org/packages/predis/pr
|
||||
management of projects dependencies using [Composer](http://packagist.org/about-composer).
|
||||
Compressed archives of each release are [available on GitHub](https://github.com/predis/predis/releases).
|
||||
|
||||
```shell
|
||||
composer require predis/predis
|
||||
```
|
||||
|
||||
|
||||
### Loading the library ###
|
||||
|
||||
@@ -487,7 +491,7 @@ The code for Predis is distributed under the terms of the MIT license (see [LICE
|
||||
[ico-version-stable]: https://img.shields.io/packagist/v/predis/predis.svg?style=flat-square
|
||||
[ico-version-dev]: https://img.shields.io/packagist/vpre/predis/predis.svg?style=flat-square
|
||||
[ico-downloads-monthly]: https://img.shields.io/packagist/dm/predis/predis.svg?style=flat-square
|
||||
[ico-build]: https://img.shields.io/github/workflow/status/predis/predis/Tests/main?style=flat-square
|
||||
[ico-build]: https://img.shields.io/github/actions/workflow/status/predis/predis/tests.yml?branch=main&style=flat-square
|
||||
|
||||
[link-packagist]: https://packagist.org/packages/predis/predis
|
||||
[link-actions]: https://github.com/predis/predis/actions
|
||||
|
||||
+6
-7
@@ -9,16 +9,16 @@
|
||||
"issues": "https://github.com/predis/predis/issues"
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "Daniele Alessandri",
|
||||
"email": "suppakilla@gmail.com",
|
||||
"homepage": "http://clorophilla.net",
|
||||
"role": "Creator & Maintainer"
|
||||
},
|
||||
{
|
||||
"name": "Till Krüss",
|
||||
"homepage": "https://till.im",
|
||||
"role": "Maintainer"
|
||||
},
|
||||
{
|
||||
"name": "Daniele Alessandri",
|
||||
"email": "suppakilla@gmail.com",
|
||||
"homepage": "http://clorophilla.net",
|
||||
"role": "Creator"
|
||||
}
|
||||
],
|
||||
"funding": [
|
||||
@@ -34,7 +34,6 @@
|
||||
"phpunit/phpunit": "^8.0 || ~9.4.4"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-phpiredis": "Allows faster serialization and deserialization of the Redis protocol",
|
||||
"ext-curl": "Allows access to Webdis when paired with phpiredis"
|
||||
},
|
||||
"autoload": {
|
||||
|
||||
+7
-5
@@ -11,6 +11,8 @@
|
||||
|
||||
namespace Predis;
|
||||
|
||||
use Traversable;
|
||||
|
||||
use Predis\Command\CommandInterface;
|
||||
use Predis\Command\RawCommand;
|
||||
use Predis\Command\ScriptCommand;
|
||||
@@ -34,13 +36,13 @@ use Predis\Transaction\MultiExec as MultiExecTransaction;
|
||||
* abstractions are built. Internally it aggregates various other classes each
|
||||
* one with its own responsibility and scope.
|
||||
*
|
||||
* {@inheritdoc}
|
||||
* @template-implements \IteratorAggregate<string, static>
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class Client implements ClientInterface, \IteratorAggregate
|
||||
{
|
||||
const VERSION = '2.0.0';
|
||||
const VERSION = '2.1.1';
|
||||
|
||||
/** @var OptionsInterface */
|
||||
private $options;
|
||||
@@ -378,7 +380,7 @@ class Client implements ClientInterface, \IteratorAggregate
|
||||
: $this->$initializer(null, $argv[0]);
|
||||
|
||||
case 2:
|
||||
list($arg0, $arg1) = $argv;
|
||||
[$arg0, $arg1] = $argv;
|
||||
|
||||
return $this->$initializer($arg0, $arg1);
|
||||
|
||||
@@ -511,7 +513,7 @@ class Client implements ClientInterface, \IteratorAggregate
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return Traversable<string, static>
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function getIterator()
|
||||
@@ -519,7 +521,7 @@ class Client implements ClientInterface, \IteratorAggregate
|
||||
$clients = array();
|
||||
$connection = $this->getConnection();
|
||||
|
||||
if (!$connection instanceof \Traversable) {
|
||||
if (!$connection instanceof Traversable) {
|
||||
return new \ArrayIterator(array(
|
||||
(string) $connection => new static($connection, $this->getOptions())
|
||||
));
|
||||
|
||||
@@ -11,11 +11,15 @@
|
||||
|
||||
namespace Predis;
|
||||
|
||||
use Predis\Command\Argument\Geospatial\ByInterface;
|
||||
use Predis\Command\Argument\Geospatial\FromInterface;
|
||||
use Predis\Command\Argument\Server\To;
|
||||
use Predis\Command\CommandInterface;
|
||||
|
||||
/**
|
||||
* Interface defining a client-side context such as a pipeline or transaction.
|
||||
*
|
||||
* @method $this copy(string $source, string $destination, int $db = -1, bool $replace = false)
|
||||
* @method $this del(array|string $keys)
|
||||
* @method $this dump($key)
|
||||
* @method $this exists($key)
|
||||
@@ -40,11 +44,18 @@ use Predis\Command\CommandInterface;
|
||||
* @method $this bitop($operation, $destkey, $key)
|
||||
* @method $this bitfield($key, $subcommand, ...$subcommandArg)
|
||||
* @method $this bitpos($key, $bit, $start = null, $end = null)
|
||||
* @method $this blmpop(int $timeout, array $keys, string $modifier = 'left', int $count = 1)
|
||||
* @method $this bzpopmax(array $keys, int $timeout)
|
||||
* @method $this bzpopmin(array $keys, int $timeout)
|
||||
* @method $this bzmpop(int $timeout, array $keys, string $modifier = 'min', int $count = 1)
|
||||
* @method $this decr($key)
|
||||
* @method $this decrby($key, $decrement)
|
||||
* @method $this failover(?To $to = null, bool $abort = false, int $timeout = -1)
|
||||
* @method $this get($key)
|
||||
* @method $this getbit($key, $offset)
|
||||
* @method $this getex(string $key, $modifier = '', $value = false)
|
||||
* @method $this getrange($key, $start, $end)
|
||||
* @method $this getdel(string $key)
|
||||
* @method $this getset($key, $value)
|
||||
* @method $this incr($key)
|
||||
* @method $this incrby($key, $increment)
|
||||
@@ -69,17 +80,21 @@ use Predis\Command\CommandInterface;
|
||||
* @method $this hlen($key)
|
||||
* @method $this hmget($key, array $fields)
|
||||
* @method $this hmset($key, array $dictionary)
|
||||
* @method $this hrandfield(string $key, int $count = 1, bool $withValues = false)
|
||||
* @method $this hscan($key, $cursor, array $options = null)
|
||||
* @method $this hset($key, $field, $value)
|
||||
* @method $this hsetnx($key, $field, $value)
|
||||
* @method $this hvals($key)
|
||||
* @method $this hstrlen($key, $field)
|
||||
* @method $this blmove(string $source, string $destination, string $where, string $to, int $timeout)
|
||||
* @method $this blpop(array|string $keys, $timeout)
|
||||
* @method $this brpop(array|string $keys, $timeout)
|
||||
* @method $this brpoplpush($source, $destination, $timeout)
|
||||
* @method $this lindex($key, $index)
|
||||
* @method $this linsert($key, $whence, $pivot, $value)
|
||||
* @method $this llen($key)
|
||||
* @method $this lmove(string $source, string $destination, string $where, string $to)
|
||||
* @method $this lmpop(array $keys, string $modifier = 'left', int $count = 1)
|
||||
* @method $this lpop($key)
|
||||
* @method $this lpush($key, array $values)
|
||||
* @method $this lpushx($key, array $values)
|
||||
@@ -99,6 +114,7 @@ use Predis\Command\CommandInterface;
|
||||
* @method $this sinterstore($destination, array|string $keys)
|
||||
* @method $this sismember($key, $member)
|
||||
* @method $this smembers($key)
|
||||
* @method $this smismember(string $key, string ...$members)
|
||||
* @method $this smove($source, $destination, $member)
|
||||
* @method $this spop($key, $count = null)
|
||||
* @method $this srandmember($key, $count = null)
|
||||
@@ -109,10 +125,18 @@ use Predis\Command\CommandInterface;
|
||||
* @method $this zadd($key, array $membersAndScoresDictionary)
|
||||
* @method $this zcard($key)
|
||||
* @method $this zcount($key, $min, $max)
|
||||
* @method $this zdiff(array $keys, bool $withScores = false)
|
||||
* @method $this zdiffstore(string $destination, array $keys)
|
||||
* @method $this zincrby($key, $increment, $member)
|
||||
* @method $this zinterstore($destination, array|string $keys, array $options = null)
|
||||
* @method $this zintercard(array $keys, int $limit = 0)
|
||||
* @method $this zinterstore(string $destination, array $keys, int[] $weights = [], string $aggregate = 'sum')
|
||||
* @method $this zinter(array $keys, int[] $weights = [], string $aggregate = 'sum', bool $withScores = false)
|
||||
* @method $this zmpop(array $keys, string $modifier = 'min', int $count = 1)
|
||||
* @method $this zmscore(string $key, string ...$member)
|
||||
* @method $this zrandmember(string $key, int $count = 1, bool $withScores = false)
|
||||
* @method $this zrange($key, $start, $stop, array $options = null)
|
||||
* @method $this zrangebyscore($key, $min, $max, array $options = null)
|
||||
* @method $this zrangestore(string $destination, string $source, int|string $min, string|int $max, string|bool $by = false, bool $reversed = false, bool $limit = false, int $offset = 0, int $count = 0)
|
||||
* @method $this zrank($key, $member)
|
||||
* @method $this zrem($key, $member)
|
||||
* @method $this zremrangebyrank($key, $start, $stop)
|
||||
@@ -120,7 +144,8 @@ use Predis\Command\CommandInterface;
|
||||
* @method $this zrevrange($key, $start, $stop, array $options = null)
|
||||
* @method $this zrevrangebyscore($key, $max, $min, array $options = null)
|
||||
* @method $this zrevrank($key, $member)
|
||||
* @method $this zunionstore($destination, array|string $keys, array $options = null)
|
||||
* @method $this zunion(array $keys, int[] $weights = [], string $aggregate = 'sum', bool $withScores = false)
|
||||
* @method $this zunionstore(string $destination, array $keys, int[] $weights = [], string $aggregate = 'sum')
|
||||
* @method $this zscore($key, $member)
|
||||
* @method $this zscan($key, $cursor, array $options = null)
|
||||
* @method $this zrangebylex($key, $start, $stop, array $options = null)
|
||||
@@ -164,6 +189,8 @@ use Predis\Command\CommandInterface;
|
||||
* @method $this geodist($key, $member1, $member2, $unit = null)
|
||||
* @method $this georadius($key, $longitude, $latitude, $radius, $unit, array $options = null)
|
||||
* @method $this georadiusbymember($key, $member, $radius, $unit, array $options = null)
|
||||
* @method $this geosearch(string $key, FromInterface $from, ByInterface $by, ?string $sorting = null, int $count = -1, bool $any = false, bool $withCoord = false, bool $withDist = false, bool $withHash = false)
|
||||
* @method $this geosearchstore(string $destination, string $source, FromInterface $from, ByInterface $by, ?string $sorting = null, int $count = -1, bool $any = false, bool $storeDist = false)
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
|
||||
+184
-151
@@ -11,6 +11,9 @@
|
||||
|
||||
namespace Predis;
|
||||
|
||||
use Predis\Command\Argument\Geospatial\ByInterface;
|
||||
use Predis\Command\Argument\Geospatial\FromInterface;
|
||||
use Predis\Command\Argument\Server\To;
|
||||
use Predis\Command\CommandInterface;
|
||||
use Predis\Command\FactoryInterface;
|
||||
use Predis\Configuration\OptionsInterface;
|
||||
@@ -25,157 +28,187 @@ use Predis\Response\Status;
|
||||
* and more friendly interface to ease programming which is described in the
|
||||
* following list of methods:
|
||||
*
|
||||
* @method int del(string[]|string $keyOrKeys, string ...$keys = null)
|
||||
* @method string|null dump(string $key)
|
||||
* @method int exists(string $key)
|
||||
* @method int expire(string $key, int $seconds)
|
||||
* @method int expireat(string $key, int $timestamp)
|
||||
* @method array keys(string $pattern)
|
||||
* @method int move(string $key, int $db)
|
||||
* @method mixed object($subcommand, string $key)
|
||||
* @method int persist(string $key)
|
||||
* @method int pexpire(string $key, int $milliseconds)
|
||||
* @method int pexpireat(string $key, int $timestamp)
|
||||
* @method int pttl(string $key)
|
||||
* @method string|null randomkey()
|
||||
* @method mixed rename(string $key, string $target)
|
||||
* @method int renamenx(string $key, string $target)
|
||||
* @method array scan($cursor, array $options = null)
|
||||
* @method array sort(string $key, array $options = null)
|
||||
* @method int ttl(string $key)
|
||||
* @method mixed type(string $key)
|
||||
* @method int append(string $key, $value)
|
||||
* @method int bitcount(string $key, $start = null, $end = null)
|
||||
* @method int bitop($operation, $destkey, $key)
|
||||
* @method array|null bitfield(string $key, $subcommand, ...$subcommandArg)
|
||||
* @method int bitpos(string $key, $bit, $start = null, $end = null)
|
||||
* @method int decr(string $key)
|
||||
* @method int decrby(string $key, int $decrement)
|
||||
* @method string|null get(string $key)
|
||||
* @method int getbit(string $key, $offset)
|
||||
* @method string getrange(string $key, $start, $end)
|
||||
* @method string|null getset(string $key, $value)
|
||||
* @method int incr(string $key)
|
||||
* @method int incrby(string $key, int $increment)
|
||||
* @method string incrbyfloat(string $key, int|float $increment)
|
||||
* @method array mget(string[]|string $keyOrKeys, string ...$keys = null)
|
||||
* @method mixed mset(array $dictionary)
|
||||
* @method int msetnx(array $dictionary)
|
||||
* @method Status psetex(string $key, $milliseconds, $value)
|
||||
* @method Status set(string $key, $value, $expireResolution = null, $expireTTL = null, $flag = null)
|
||||
* @method int setbit(string $key, $offset, $value)
|
||||
* @method Status setex(string $key, $seconds, $value)
|
||||
* @method int setnx(string $key, $value)
|
||||
* @method int setrange(string $key, $offset, $value)
|
||||
* @method int strlen(string $key)
|
||||
* @method int hdel(string $key, array $fields)
|
||||
* @method int hexists(string $key, string $field)
|
||||
* @method string|null hget(string $key, string $field)
|
||||
* @method array hgetall(string $key)
|
||||
* @method int hincrby(string $key, string $field, int $increment)
|
||||
* @method string hincrbyfloat(string $key, string $field, int|float $increment)
|
||||
* @method array hkeys(string $key)
|
||||
* @method int hlen(string $key)
|
||||
* @method array hmget(string $key, array $fields)
|
||||
* @method mixed hmset(string $key, array $dictionary)
|
||||
* @method array hscan(string $key, $cursor, array $options = null)
|
||||
* @method int hset(string $key, string $field, string $value)
|
||||
* @method int hsetnx(string $key, string $field, string $value)
|
||||
* @method array hvals(string $key)
|
||||
* @method int hstrlen(string $key, string $field)
|
||||
* @method array|null blpop(array|string $keys, int|float $timeout)
|
||||
* @method array|null brpop(array|string $keys, int|float $timeout)
|
||||
* @method string|null brpoplpush(string $source, string $destination, int|float $timeout)
|
||||
* @method string|null lindex(string $key, int $index)
|
||||
* @method int linsert(string $key, $whence, $pivot, $value)
|
||||
* @method int llen(string $key)
|
||||
* @method string|null lpop(string $key)
|
||||
* @method int lpush(string $key, array $values)
|
||||
* @method int lpushx(string $key, array $values)
|
||||
* @method string[] lrange(string $key, int $start, int $stop)
|
||||
* @method int lrem(string $key, int $count, string $value)
|
||||
* @method mixed lset(string $key, int $index, string $value)
|
||||
* @method mixed ltrim(string $key, int $start, int $stop)
|
||||
* @method string|null rpop(string $key)
|
||||
* @method string|null rpoplpush(string $source, string $destination)
|
||||
* @method int rpush(string $key, array $values)
|
||||
* @method int rpushx(string $key, array $values)
|
||||
* @method int sadd(string $key, array $members)
|
||||
* @method int scard(string $key)
|
||||
* @method string[] sdiff(array|string $keys)
|
||||
* @method int sdiffstore(string $destination, array|string $keys)
|
||||
* @method string[] sinter(array|string $keys)
|
||||
* @method int sinterstore(string $destination, array|string $keys)
|
||||
* @method int sismember(string $key, string $member)
|
||||
* @method string[] smembers(string $key)
|
||||
* @method int smove(string $source, string $destination, string $member)
|
||||
* @method string|null spop(string $key, int $count = null)
|
||||
* @method string|null srandmember(string $key, int $count = null)
|
||||
* @method int srem(string $key, string $member)
|
||||
* @method array sscan(string $key, int $cursor, array $options = null)
|
||||
* @method string[] sunion(array|string $keys)
|
||||
* @method int sunionstore(string $destination, array|string $keys)
|
||||
* @method int touch(string[]|string $keyOrKeys, string ...$keys = null)
|
||||
* @method int zadd(string $key, array $membersAndScoresDictionary)
|
||||
* @method int zcard(string $key)
|
||||
* @method string zcount(string $key, int|string $min, int|string $max)
|
||||
* @method string zincrby(string $key, int $increment, string $member)
|
||||
* @method int zinterstore(string $destination, array|string $keys, array $options = null)
|
||||
* @method array zpopmin(string $key, int $count = 1)
|
||||
* @method array zpopmax(string $key, int $count = 1)
|
||||
* @method array zrange(string $key, int|string $start, int|string $stop, array $options = null)
|
||||
* @method array zrangebyscore(string $key, int|string $min, int|string $max, array $options = null)
|
||||
* @method int|null zrank(string $key, string $member)
|
||||
* @method int zrem(string $key, string ...$member)
|
||||
* @method int zremrangebyrank(string $key, int|string $start, int|string $stop)
|
||||
* @method int zremrangebyscore(string $key, int|string $min, int|string $max)
|
||||
* @method array zrevrange(string $key, int|string $start, int|string $stop, array $options = null)
|
||||
* @method array zrevrangebyscore(string $key, int|string $max, int|string $min, array $options = null)
|
||||
* @method int|null zrevrank(string $key, string $member)
|
||||
* @method int zunionstore(string $destination, array|string $keys, array $options = null)
|
||||
* @method string|null zscore(string $key, string $member)
|
||||
* @method array zscan(string $key, int $cursor, array $options = null)
|
||||
* @method array zrangebylex(string $key, string $start, string $stop, array $options = null)
|
||||
* @method array zrevrangebylex(string $key, string $start, string $stop, array $options = null)
|
||||
* @method int zremrangebylex(string $key, string $min, string $max)
|
||||
* @method int zlexcount(string $key, string $min, string $max)
|
||||
* @method int pfadd(string $key, array $elements)
|
||||
* @method mixed pfmerge(string $destinationKey, array|string $sourceKeys)
|
||||
* @method int pfcount(string[]|string $keyOrKeys, string ...$keys = null)
|
||||
* @method mixed pubsub($subcommand, $argument)
|
||||
* @method int publish($channel, $message)
|
||||
* @method mixed discard()
|
||||
* @method array|null exec()
|
||||
* @method mixed multi()
|
||||
* @method mixed unwatch()
|
||||
* @method mixed watch(string $key)
|
||||
* @method mixed eval(string $script, int $numkeys, string ...$keyOrArg = null)
|
||||
* @method mixed evalsha(string $script, int $numkeys, string ...$keyOrArg = null)
|
||||
* @method mixed script($subcommand, $argument = null)
|
||||
* @method mixed auth(string $password)
|
||||
* @method string echo(string $message)
|
||||
* @method mixed ping(string $message = null)
|
||||
* @method mixed select(int $database)
|
||||
* @method mixed bgrewriteaof()
|
||||
* @method mixed bgsave()
|
||||
* @method mixed client($subcommand, $argument = null)
|
||||
* @method mixed config($subcommand, $argument = null)
|
||||
* @method int dbsize()
|
||||
* @method mixed flushall()
|
||||
* @method mixed flushdb()
|
||||
* @method array info($section = null)
|
||||
* @method int lastsave()
|
||||
* @method mixed save()
|
||||
* @method mixed slaveof(string $host, int $port)
|
||||
* @method mixed slowlog($subcommand, $argument = null)
|
||||
* @method array time()
|
||||
* @method array command()
|
||||
* @method int geoadd(string $key, $longitude, $latitude, $member)
|
||||
* @method array geohash(string $key, array $members)
|
||||
* @method array geopos(string $key, array $members)
|
||||
* @method string|null geodist(string $key, $member1, $member2, $unit = null)
|
||||
* @method array georadius(string $key, $longitude, $latitude, $radius, $unit, array $options = null)
|
||||
* @method array georadiusbymember(string $key, $member, $radius, $unit, array $options = null)
|
||||
* @method int copy(string $source, string $destination, int $db = -1, bool $replace = false)
|
||||
* @method int del(string[]|string $keyOrKeys, string ...$keys = null)
|
||||
* @method string|null dump(string $key)
|
||||
* @method int exists(string $key)
|
||||
* @method int expire(string $key, int $seconds)
|
||||
* @method int expireat(string $key, int $timestamp)
|
||||
* @method array keys(string $pattern)
|
||||
* @method int move(string $key, int $db)
|
||||
* @method mixed object($subcommand, string $key)
|
||||
* @method int persist(string $key)
|
||||
* @method int pexpire(string $key, int $milliseconds)
|
||||
* @method int pexpireat(string $key, int $timestamp)
|
||||
* @method int pttl(string $key)
|
||||
* @method string|null randomkey()
|
||||
* @method mixed rename(string $key, string $target)
|
||||
* @method int renamenx(string $key, string $target)
|
||||
* @method array scan($cursor, array $options = null)
|
||||
* @method array sort(string $key, array $options = null)
|
||||
* @method int ttl(string $key)
|
||||
* @method mixed type(string $key)
|
||||
* @method int append(string $key, $value)
|
||||
* @method int bitcount(string $key, $start = null, $end = null)
|
||||
* @method int bitop($operation, $destkey, $key)
|
||||
* @method array|null bitfield(string $key, $subcommand, ...$subcommandArg)
|
||||
* @method int bitpos(string $key, $bit, $start = null, $end = null)
|
||||
* @method array blmpop(int $timeout, array $keys, string $modifier = 'left', int $count = 1)
|
||||
* @method array bzpopmax(array $keys, int $timeout)
|
||||
* @method array bzpopmin(array $keys, int $timeout)
|
||||
* @method array bzmpop(int $timeout, array $keys, string $modifier = 'min', int $count = 1)
|
||||
* @method int decr(string $key)
|
||||
* @method int decrby(string $key, int $decrement)
|
||||
* @method Status failover(?To $to = null, bool $abort = false, int $timeout = -1)
|
||||
* @method string|null get(string $key)
|
||||
* @method int getbit(string $key, $offset)
|
||||
* @method int|null getex(string $key, $modifier = '', $value = false)
|
||||
* @method string getrange(string $key, $start, $end)
|
||||
* @method string getdel(string $key)
|
||||
* @method string|null getset(string $key, $value)
|
||||
* @method int incr(string $key)
|
||||
* @method int incrby(string $key, int $increment)
|
||||
* @method string incrbyfloat(string $key, int|float $increment)
|
||||
* @method array mget(string[]|string $keyOrKeys, string ...$keys = null)
|
||||
* @method mixed mset(array $dictionary)
|
||||
* @method int msetnx(array $dictionary)
|
||||
* @method Status psetex(string $key, $milliseconds, $value)
|
||||
* @method Status set(string $key, $value, $expireResolution = null, $expireTTL = null, $flag = null)
|
||||
* @method int setbit(string $key, $offset, $value)
|
||||
* @method Status setex(string $key, $seconds, $value)
|
||||
* @method int setnx(string $key, $value)
|
||||
* @method int setrange(string $key, $offset, $value)
|
||||
* @method int strlen(string $key)
|
||||
* @method int hdel(string $key, array $fields)
|
||||
* @method int hexists(string $key, string $field)
|
||||
* @method string|null hget(string $key, string $field)
|
||||
* @method array hgetall(string $key)
|
||||
* @method int hincrby(string $key, string $field, int $increment)
|
||||
* @method string hincrbyfloat(string $key, string $field, int|float $increment)
|
||||
* @method array hkeys(string $key)
|
||||
* @method int hlen(string $key)
|
||||
* @method array hmget(string $key, array $fields)
|
||||
* @method mixed hmset(string $key, array $dictionary)
|
||||
* @method array hrandfield(string $key, int $count = 1, bool $withValues = false)
|
||||
* @method array hscan(string $key, $cursor, array $options = null)
|
||||
* @method int hset(string $key, string $field, string $value)
|
||||
* @method int hsetnx(string $key, string $field, string $value)
|
||||
* @method array hvals(string $key)
|
||||
* @method int hstrlen(string $key, string $field)
|
||||
* @method string blmove(string $source, string $destination, string $where, string $to, int $timeout)
|
||||
* @method array|null blpop(array|string $keys, int|float $timeout)
|
||||
* @method array|null brpop(array|string $keys, int|float $timeout)
|
||||
* @method string|null brpoplpush(string $source, string $destination, int|float $timeout)
|
||||
* @method string|null lindex(string $key, int $index)
|
||||
* @method int linsert(string $key, $whence, $pivot, $value)
|
||||
* @method int llen(string $key)
|
||||
* @method string lmove(string $source, string $destination, string $where, string $to)
|
||||
* @method array|null lmpop(array $keys, string $modifier = 'left', int $count = 1)
|
||||
* @method string|null lpop(string $key)
|
||||
* @method int lpush(string $key, array $values)
|
||||
* @method int lpushx(string $key, array $values)
|
||||
* @method string[] lrange(string $key, int $start, int $stop)
|
||||
* @method int lrem(string $key, int $count, string $value)
|
||||
* @method mixed lset(string $key, int $index, string $value)
|
||||
* @method mixed ltrim(string $key, int $start, int $stop)
|
||||
* @method string|null rpop(string $key)
|
||||
* @method string|null rpoplpush(string $source, string $destination)
|
||||
* @method int rpush(string $key, array $values)
|
||||
* @method int rpushx(string $key, array $values)
|
||||
* @method int sadd(string $key, array $members)
|
||||
* @method int scard(string $key)
|
||||
* @method string[] sdiff(array|string $keys)
|
||||
* @method int sdiffstore(string $destination, array|string $keys)
|
||||
* @method string[] sinter(array|string $keys)
|
||||
* @method int sinterstore(string $destination, array|string $keys)
|
||||
* @method int sismember(string $key, string $member)
|
||||
* @method string[] smembers(string $key)
|
||||
* @method array smismember(string $key, string ...$members)
|
||||
* @method int smove(string $source, string $destination, string $member)
|
||||
* @method string|array|null spop(string $key, int $count = null)
|
||||
* @method string|null srandmember(string $key, int $count = null)
|
||||
* @method int srem(string $key, array|string $member)
|
||||
* @method array sscan(string $key, int $cursor, array $options = null)
|
||||
* @method string[] sunion(array|string $keys)
|
||||
* @method int sunionstore(string $destination, array|string $keys)
|
||||
* @method int touch(string[]|string $keyOrKeys, string ...$keys = null)
|
||||
* @method string xadd(string $key, array $dictionary, string $id = '*', array $options = null)
|
||||
* @method int xdel(string $key, string ...$id)
|
||||
* @method int xlen(string $key)
|
||||
* @method array xrevrange(string $key, string $end, string $start, ?int $count = null)
|
||||
* @method array xrange(string $key, string $start, string $end, ?int $count = null)
|
||||
* @method string xtrim(string $key, array|string $strategy, string $threshold, array $options = null)
|
||||
* @method int zadd(string $key, array $membersAndScoresDictionary)
|
||||
* @method int zcard(string $key)
|
||||
* @method string zcount(string $key, int|string $min, int|string $max)
|
||||
* @method array zdiff(array $keys, bool $withScores = false)
|
||||
* @method int zdiffstore(string $destination, array $keys)
|
||||
* @method string zincrby(string $key, int $increment, string $member)
|
||||
* @method int zintercard(array $keys, int $limit = 0)
|
||||
* @method int zinterstore(string $destination, array $keys, int[] $weights = [], string $aggregate = 'sum')
|
||||
* @method array zinter(array $keys, int[] $weights = [], string $aggregate = 'sum', bool $withScores = false)
|
||||
* @method array zmpop(array $keys, string $modifier = 'min', int $count = 1)
|
||||
* @method array zmscore(string $key, string ...$member)
|
||||
* @method array zpopmin(string $key, int $count = 1)
|
||||
* @method array zpopmax(string $key, int $count = 1)
|
||||
* @method mixed zrandmember(string $key, int $count = 1, bool $withScores = false)
|
||||
* @method array zrange(string $key, int|string $start, int|string $stop, array $options = null)
|
||||
* @method array zrangebyscore(string $key, int|string $min, int|string $max, array $options = null)
|
||||
* @method int zrangestore(string $destination, string $source, int|string $min, int|string $max, string|bool $by = false, bool $reversed = false, bool $limit = false, int $offset = 0, int $count = 0)
|
||||
* @method int|null zrank(string $key, string $member)
|
||||
* @method int zrem(string $key, string ...$member)
|
||||
* @method int zremrangebyrank(string $key, int|string $start, int|string $stop)
|
||||
* @method int zremrangebyscore(string $key, int|string $min, int|string $max)
|
||||
* @method array zrevrange(string $key, int|string $start, int|string $stop, array $options = null)
|
||||
* @method array zrevrangebyscore(string $key, int|string $max, int|string $min, array $options = null)
|
||||
* @method int|null zrevrank(string $key, string $member)
|
||||
* @method array zunion(array $keys, int[] $weights = [], string $aggregate = 'sum', bool $withScores = false)
|
||||
* @method int zunionstore(string $destination, array $keys, int[] $weights = [], string $aggregate = 'sum')
|
||||
* @method string|null zscore(string $key, string $member)
|
||||
* @method array zscan(string $key, int $cursor, array $options = null)
|
||||
* @method array zrangebylex(string $key, string $start, string $stop, array $options = null)
|
||||
* @method array zrevrangebylex(string $key, string $start, string $stop, array $options = null)
|
||||
* @method int zremrangebylex(string $key, string $min, string $max)
|
||||
* @method int zlexcount(string $key, string $min, string $max)
|
||||
* @method int pfadd(string $key, array $elements)
|
||||
* @method mixed pfmerge(string $destinationKey, array|string $sourceKeys)
|
||||
* @method int pfcount(string[]|string $keyOrKeys, string ...$keys = null)
|
||||
* @method mixed pubsub($subcommand, $argument)
|
||||
* @method int publish($channel, $message)
|
||||
* @method mixed discard()
|
||||
* @method array|null exec()
|
||||
* @method mixed multi()
|
||||
* @method mixed unwatch()
|
||||
* @method mixed watch(string $key)
|
||||
* @method mixed eval(string $script, int $numkeys, string ...$keyOrArg = null)
|
||||
* @method mixed evalsha(string $script, int $numkeys, string ...$keyOrArg = null)
|
||||
* @method mixed script($subcommand, $argument = null)
|
||||
* @method mixed auth(string $password)
|
||||
* @method string echo(string $message)
|
||||
* @method mixed ping(string $message = null)
|
||||
* @method mixed select(int $database)
|
||||
* @method mixed bgrewriteaof()
|
||||
* @method mixed bgsave()
|
||||
* @method mixed client($subcommand, $argument = null)
|
||||
* @method mixed config($subcommand, $argument = null)
|
||||
* @method int dbsize()
|
||||
* @method mixed flushall()
|
||||
* @method mixed flushdb()
|
||||
* @method array info($section = null)
|
||||
* @method int lastsave()
|
||||
* @method mixed save()
|
||||
* @method mixed slaveof(string $host, int $port)
|
||||
* @method mixed slowlog($subcommand, $argument = null)
|
||||
* @method array time()
|
||||
* @method array command()
|
||||
* @method int geoadd(string $key, $longitude, $latitude, $member)
|
||||
* @method array geohash(string $key, array $members)
|
||||
* @method array geopos(string $key, array $members)
|
||||
* @method string|null geodist(string $key, $member1, $member2, $unit = null)
|
||||
* @method array georadius(string $key, $longitude, $latitude, $radius, $unit, array $options = null)
|
||||
* @method array georadiusbymember(string $key, $member, $radius, $unit, array $options = null)
|
||||
* @method array geosearch(string $key, FromInterface $from, ByInterface $by, ?string $sorting = null, int $count = -1, bool $any = false, bool $withCoord = false, bool $withDist = false, bool $withHash = false)
|
||||
* @method int geosearchstore(string $destination, string $source, FromInterface $from, ByInterface $by, ?string $sorting = null, int $count = -1, bool $any = false, bool $storeDist = false)
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Argument;
|
||||
|
||||
/**
|
||||
* Allows to use object-oriented approach to handle complex conditional arguments.
|
||||
*/
|
||||
interface ArrayableArgument
|
||||
{
|
||||
/**
|
||||
* Get the instance as an array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray(): array;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Argument\Geospatial;
|
||||
|
||||
use UnexpectedValueException;
|
||||
|
||||
abstract class AbstractBy implements ByInterface
|
||||
{
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
private static $unitEnum = ['m', 'km', 'ft', 'mi'];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $unit;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
abstract public function toArray(): array;
|
||||
|
||||
/**
|
||||
* @param string $unit
|
||||
* @return void
|
||||
*/
|
||||
protected function setUnit(string $unit): void
|
||||
{
|
||||
if (!in_array($unit, self::$unitEnum, true)) {
|
||||
throw new UnexpectedValueException('Wrong value given for unit');
|
||||
}
|
||||
|
||||
$this->unit = $unit;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Argument\Geospatial;
|
||||
|
||||
class ByBox extends AbstractBy
|
||||
{
|
||||
private const KEYWORD = 'BYBOX';
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $width;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $height;
|
||||
|
||||
public function __construct(int $width, int $height, string $unit)
|
||||
{
|
||||
$this->width = $width;
|
||||
$this->height = $height;
|
||||
$this->setUnit($unit);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
return [self::KEYWORD, $this->width, $this->height, $this->unit];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Argument\Geospatial;
|
||||
|
||||
use Predis\Command\Argument\ArrayableArgument;
|
||||
|
||||
interface ByInterface extends ArrayableArgument
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Argument\Geospatial;
|
||||
|
||||
class ByRadius extends AbstractBy
|
||||
{
|
||||
private const KEYWORD = 'BYRADIUS';
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $radius;
|
||||
|
||||
public function __construct(int $radius, string $unit)
|
||||
{
|
||||
$this->radius = $radius;
|
||||
$this->setUnit($unit);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
return [self::KEYWORD, $this->radius, $this->unit];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Argument\Geospatial;
|
||||
|
||||
use Predis\Command\Argument\ArrayableArgument;
|
||||
|
||||
interface FromInterface extends ArrayableArgument
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Argument\Geospatial;
|
||||
|
||||
class FromLonLat implements FromInterface
|
||||
{
|
||||
private const KEYWORD = 'FROMLONLAT';
|
||||
|
||||
/**
|
||||
* @var float
|
||||
*/
|
||||
private $longitude;
|
||||
|
||||
/**
|
||||
* @var float
|
||||
*/
|
||||
private $latitude;
|
||||
|
||||
public function __construct(float $longitude, float $latitude)
|
||||
{
|
||||
$this->longitude = $longitude;
|
||||
$this->latitude = $latitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
return [self::KEYWORD, $this->longitude, $this->latitude];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Argument\Geospatial;
|
||||
|
||||
class FromMember implements FromInterface
|
||||
{
|
||||
private const KEYWORD = 'FROMMEMBER';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $member;
|
||||
|
||||
public function __construct(string $member)
|
||||
{
|
||||
$this->member = $member;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
return [self::KEYWORD, $this->member];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Argument\Server;
|
||||
|
||||
use Predis\Command\Argument\ArrayableArgument;
|
||||
|
||||
class To implements ArrayableArgument
|
||||
{
|
||||
private const KEYWORD = 'TO';
|
||||
private const FORCE_KEYWORD = 'FORCE';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $host;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $port;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $isForce;
|
||||
|
||||
public function __construct(string $host, int $port, bool $isForce = false)
|
||||
{
|
||||
$this->host = $host;
|
||||
$this->port = $port;
|
||||
$this->isForce = $isForce;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
$arguments = [self::KEYWORD, $this->host, $this->port];
|
||||
|
||||
if ($this->isForce) {
|
||||
$arguments[] = self::FORCE_KEYWORD;
|
||||
}
|
||||
|
||||
return $arguments;
|
||||
}
|
||||
}
|
||||
@@ -114,4 +114,16 @@ abstract class Command implements CommandInterface
|
||||
|
||||
return $arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all false values from arguments.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function filterArguments(): void
|
||||
{
|
||||
$this->arguments = array_filter($this->arguments, static function ($argument) {
|
||||
return $argument !== false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,142 +31,154 @@ class KeyPrefixProcessor implements ProcessorInterface
|
||||
public function __construct($prefix)
|
||||
{
|
||||
$this->prefix = $prefix;
|
||||
$this->commands = array(
|
||||
|
||||
$prefixFirst = static::class . '::first';
|
||||
$prefixAll = static::class . '::all';
|
||||
$prefixInterleaved = static::class . '::interleaved';
|
||||
$prefixSkipFirst = static::class . '::skipFirst';
|
||||
$prefixSkipLast = static::class . '::skipLast';
|
||||
$prefixSort = static::class . '::sort';
|
||||
$prefixEvalKeys = static::class . '::evalKeys';
|
||||
$prefixZsetStore = static::class . '::zsetStore';
|
||||
$prefixMigrate = static::class . '::migrate';
|
||||
$prefixGeoradius = static::class . '::georadius';
|
||||
|
||||
$this->commands = [
|
||||
/* ---------------- Redis 1.2 ---------------- */
|
||||
'EXISTS' => 'static::all',
|
||||
'DEL' => 'static::all',
|
||||
'TYPE' => 'static::first',
|
||||
'KEYS' => 'static::first',
|
||||
'RENAME' => 'static::all',
|
||||
'RENAMENX' => 'static::all',
|
||||
'EXPIRE' => 'static::first',
|
||||
'EXPIREAT' => 'static::first',
|
||||
'TTL' => 'static::first',
|
||||
'MOVE' => 'static::first',
|
||||
'SORT' => 'static::sort',
|
||||
'DUMP' => 'static::first',
|
||||
'RESTORE' => 'static::first',
|
||||
'SET' => 'static::first',
|
||||
'SETNX' => 'static::first',
|
||||
'MSET' => 'static::interleaved',
|
||||
'MSETNX' => 'static::interleaved',
|
||||
'GET' => 'static::first',
|
||||
'MGET' => 'static::all',
|
||||
'GETSET' => 'static::first',
|
||||
'INCR' => 'static::first',
|
||||
'INCRBY' => 'static::first',
|
||||
'DECR' => 'static::first',
|
||||
'DECRBY' => 'static::first',
|
||||
'RPUSH' => 'static::first',
|
||||
'LPUSH' => 'static::first',
|
||||
'LLEN' => 'static::first',
|
||||
'LRANGE' => 'static::first',
|
||||
'LTRIM' => 'static::first',
|
||||
'LINDEX' => 'static::first',
|
||||
'LSET' => 'static::first',
|
||||
'LREM' => 'static::first',
|
||||
'LPOP' => 'static::first',
|
||||
'RPOP' => 'static::first',
|
||||
'RPOPLPUSH' => 'static::all',
|
||||
'SADD' => 'static::first',
|
||||
'SREM' => 'static::first',
|
||||
'SPOP' => 'static::first',
|
||||
'SMOVE' => 'static::skipLast',
|
||||
'SCARD' => 'static::first',
|
||||
'SISMEMBER' => 'static::first',
|
||||
'SINTER' => 'static::all',
|
||||
'SINTERSTORE' => 'static::all',
|
||||
'SUNION' => 'static::all',
|
||||
'SUNIONSTORE' => 'static::all',
|
||||
'SDIFF' => 'static::all',
|
||||
'SDIFFSTORE' => 'static::all',
|
||||
'SMEMBERS' => 'static::first',
|
||||
'SRANDMEMBER' => 'static::first',
|
||||
'ZADD' => 'static::first',
|
||||
'ZINCRBY' => 'static::first',
|
||||
'ZREM' => 'static::first',
|
||||
'ZRANGE' => 'static::first',
|
||||
'ZREVRANGE' => 'static::first',
|
||||
'ZRANGEBYSCORE' => 'static::first',
|
||||
'ZCARD' => 'static::first',
|
||||
'ZSCORE' => 'static::first',
|
||||
'ZREMRANGEBYSCORE' => 'static::first',
|
||||
'EXISTS' => $prefixAll,
|
||||
'DEL' => $prefixAll,
|
||||
'TYPE' => $prefixFirst,
|
||||
'KEYS' => $prefixFirst,
|
||||
'RENAME' => $prefixAll,
|
||||
'RENAMENX' => $prefixAll,
|
||||
'EXPIRE' => $prefixFirst,
|
||||
'EXPIREAT' => $prefixFirst,
|
||||
'TTL' => $prefixFirst,
|
||||
'MOVE' => $prefixFirst,
|
||||
'SORT' => $prefixSort,
|
||||
'DUMP' => $prefixFirst,
|
||||
'RESTORE' => $prefixFirst,
|
||||
'SET' => $prefixFirst,
|
||||
'SETNX' => $prefixFirst,
|
||||
'MSET' => $prefixInterleaved,
|
||||
'MSETNX' => $prefixInterleaved,
|
||||
'GET' => $prefixFirst,
|
||||
'MGET' => $prefixAll,
|
||||
'GETSET' => $prefixFirst,
|
||||
'INCR' => $prefixFirst,
|
||||
'INCRBY' => $prefixFirst,
|
||||
'DECR' => $prefixFirst,
|
||||
'DECRBY' => $prefixFirst,
|
||||
'RPUSH' => $prefixFirst,
|
||||
'LPUSH' => $prefixFirst,
|
||||
'LLEN' => $prefixFirst,
|
||||
'LRANGE' => $prefixFirst,
|
||||
'LTRIM' => $prefixFirst,
|
||||
'LINDEX' => $prefixFirst,
|
||||
'LSET' => $prefixFirst,
|
||||
'LREM' => $prefixFirst,
|
||||
'LPOP' => $prefixFirst,
|
||||
'RPOP' => $prefixFirst,
|
||||
'RPOPLPUSH' => $prefixAll,
|
||||
'SADD' => $prefixFirst,
|
||||
'SREM' => $prefixFirst,
|
||||
'SPOP' => $prefixFirst,
|
||||
'SMOVE' => $prefixSkipLast,
|
||||
'SCARD' => $prefixFirst,
|
||||
'SISMEMBER' => $prefixFirst,
|
||||
'SINTER' => $prefixAll,
|
||||
'SINTERSTORE' => $prefixAll,
|
||||
'SUNION' => $prefixAll,
|
||||
'SUNIONSTORE' => $prefixAll,
|
||||
'SDIFF' => $prefixAll,
|
||||
'SDIFFSTORE' => $prefixAll,
|
||||
'SMEMBERS' => $prefixFirst,
|
||||
'SRANDMEMBER' => $prefixFirst,
|
||||
'ZADD' => $prefixFirst,
|
||||
'ZINCRBY' => $prefixFirst,
|
||||
'ZREM' => $prefixFirst,
|
||||
'ZRANGE' => $prefixFirst,
|
||||
'ZREVRANGE' => $prefixFirst,
|
||||
'ZRANGEBYSCORE' => $prefixFirst,
|
||||
'ZCARD' => $prefixFirst,
|
||||
'ZSCORE' => $prefixFirst,
|
||||
'ZREMRANGEBYSCORE' => $prefixFirst,
|
||||
/* ---------------- Redis 2.0 ---------------- */
|
||||
'SETEX' => 'static::first',
|
||||
'APPEND' => 'static::first',
|
||||
'SUBSTR' => 'static::first',
|
||||
'BLPOP' => 'static::skipLast',
|
||||
'BRPOP' => 'static::skipLast',
|
||||
'ZUNIONSTORE' => 'static::zsetStore',
|
||||
'ZINTERSTORE' => 'static::zsetStore',
|
||||
'ZCOUNT' => 'static::first',
|
||||
'ZRANK' => 'static::first',
|
||||
'ZREVRANK' => 'static::first',
|
||||
'ZREMRANGEBYRANK' => 'static::first',
|
||||
'HSET' => 'static::first',
|
||||
'HSETNX' => 'static::first',
|
||||
'HMSET' => 'static::first',
|
||||
'HINCRBY' => 'static::first',
|
||||
'HGET' => 'static::first',
|
||||
'HMGET' => 'static::first',
|
||||
'HDEL' => 'static::first',
|
||||
'HEXISTS' => 'static::first',
|
||||
'HLEN' => 'static::first',
|
||||
'HKEYS' => 'static::first',
|
||||
'HVALS' => 'static::first',
|
||||
'HGETALL' => 'static::first',
|
||||
'SUBSCRIBE' => 'static::all',
|
||||
'UNSUBSCRIBE' => 'static::all',
|
||||
'PSUBSCRIBE' => 'static::all',
|
||||
'PUNSUBSCRIBE' => 'static::all',
|
||||
'PUBLISH' => 'static::first',
|
||||
'SETEX' => $prefixFirst,
|
||||
'APPEND' => $prefixFirst,
|
||||
'SUBSTR' => $prefixFirst,
|
||||
'BLPOP' => $prefixSkipLast,
|
||||
'BRPOP' => $prefixSkipLast,
|
||||
'ZUNIONSTORE' => $prefixZsetStore,
|
||||
'ZINTERSTORE' => $prefixZsetStore,
|
||||
'ZCOUNT' => $prefixFirst,
|
||||
'ZRANK' => $prefixFirst,
|
||||
'ZREVRANK' => $prefixFirst,
|
||||
'ZREMRANGEBYRANK' => $prefixFirst,
|
||||
'HSET' => $prefixFirst,
|
||||
'HSETNX' => $prefixFirst,
|
||||
'HMSET' => $prefixFirst,
|
||||
'HINCRBY' => $prefixFirst,
|
||||
'HGET' => $prefixFirst,
|
||||
'HMGET' => $prefixFirst,
|
||||
'HDEL' => $prefixFirst,
|
||||
'HEXISTS' => $prefixFirst,
|
||||
'HLEN' => $prefixFirst,
|
||||
'HKEYS' => $prefixFirst,
|
||||
'HVALS' => $prefixFirst,
|
||||
'HGETALL' => $prefixFirst,
|
||||
'SUBSCRIBE' => $prefixAll,
|
||||
'UNSUBSCRIBE' => $prefixAll,
|
||||
'PSUBSCRIBE' => $prefixAll,
|
||||
'PUNSUBSCRIBE' => $prefixAll,
|
||||
'PUBLISH' => $prefixFirst,
|
||||
/* ---------------- Redis 2.2 ---------------- */
|
||||
'PERSIST' => 'static::first',
|
||||
'STRLEN' => 'static::first',
|
||||
'SETRANGE' => 'static::first',
|
||||
'GETRANGE' => 'static::first',
|
||||
'SETBIT' => 'static::first',
|
||||
'GETBIT' => 'static::first',
|
||||
'RPUSHX' => 'static::first',
|
||||
'LPUSHX' => 'static::first',
|
||||
'LINSERT' => 'static::first',
|
||||
'BRPOPLPUSH' => 'static::skipLast',
|
||||
'ZREVRANGEBYSCORE' => 'static::first',
|
||||
'WATCH' => 'static::all',
|
||||
'PERSIST' => $prefixFirst,
|
||||
'STRLEN' => $prefixFirst,
|
||||
'SETRANGE' => $prefixFirst,
|
||||
'GETRANGE' => $prefixFirst,
|
||||
'SETBIT' => $prefixFirst,
|
||||
'GETBIT' => $prefixFirst,
|
||||
'RPUSHX' => $prefixFirst,
|
||||
'LPUSHX' => $prefixFirst,
|
||||
'LINSERT' => $prefixFirst,
|
||||
'BRPOPLPUSH' => $prefixSkipLast,
|
||||
'ZREVRANGEBYSCORE' => $prefixFirst,
|
||||
'WATCH' => $prefixAll,
|
||||
/* ---------------- Redis 2.6 ---------------- */
|
||||
'PTTL' => 'static::first',
|
||||
'PEXPIRE' => 'static::first',
|
||||
'PEXPIREAT' => 'static::first',
|
||||
'PSETEX' => 'static::first',
|
||||
'INCRBYFLOAT' => 'static::first',
|
||||
'BITOP' => 'static::skipFirst',
|
||||
'BITCOUNT' => 'static::first',
|
||||
'HINCRBYFLOAT' => 'static::first',
|
||||
'EVAL' => 'static::evalKeys',
|
||||
'EVALSHA' => 'static::evalKeys',
|
||||
'MIGRATE' => 'static::migrate',
|
||||
'PTTL' => $prefixFirst,
|
||||
'PEXPIRE' => $prefixFirst,
|
||||
'PEXPIREAT' => $prefixFirst,
|
||||
'PSETEX' => $prefixFirst,
|
||||
'INCRBYFLOAT' => $prefixFirst,
|
||||
'BITOP' => $prefixSkipFirst,
|
||||
'BITCOUNT' => $prefixFirst,
|
||||
'HINCRBYFLOAT' => $prefixFirst,
|
||||
'EVAL' => $prefixEvalKeys,
|
||||
'EVALSHA' => $prefixEvalKeys,
|
||||
'MIGRATE' => $prefixMigrate,
|
||||
/* ---------------- Redis 2.8 ---------------- */
|
||||
'SSCAN' => 'static::first',
|
||||
'ZSCAN' => 'static::first',
|
||||
'HSCAN' => 'static::first',
|
||||
'PFADD' => 'static::first',
|
||||
'PFCOUNT' => 'static::all',
|
||||
'PFMERGE' => 'static::all',
|
||||
'ZLEXCOUNT' => 'static::first',
|
||||
'ZRANGEBYLEX' => 'static::first',
|
||||
'ZREMRANGEBYLEX' => 'static::first',
|
||||
'ZREVRANGEBYLEX' => 'static::first',
|
||||
'BITPOS' => 'static::first',
|
||||
'SSCAN' => $prefixFirst,
|
||||
'ZSCAN' => $prefixFirst,
|
||||
'HSCAN' => $prefixFirst,
|
||||
'PFADD' => $prefixFirst,
|
||||
'PFCOUNT' => $prefixAll,
|
||||
'PFMERGE' => $prefixAll,
|
||||
'ZLEXCOUNT' => $prefixFirst,
|
||||
'ZRANGEBYLEX' => $prefixFirst,
|
||||
'ZREMRANGEBYLEX' => $prefixFirst,
|
||||
'ZREVRANGEBYLEX' => $prefixFirst,
|
||||
'BITPOS' => $prefixFirst,
|
||||
/* ---------------- Redis 3.2 ---------------- */
|
||||
'HSTRLEN' => 'static::first',
|
||||
'BITFIELD' => 'static::first',
|
||||
'GEOADD' => 'static::first',
|
||||
'GEOHASH' => 'static::first',
|
||||
'GEOPOS' => 'static::first',
|
||||
'GEODIST' => 'static::first',
|
||||
'GEORADIUS' => 'static::georadius',
|
||||
'GEORADIUSBYMEMBER' => 'static::georadius',
|
||||
);
|
||||
'HSTRLEN' => $prefixFirst,
|
||||
'BITFIELD' => $prefixFirst,
|
||||
'GEOADD' => $prefixFirst,
|
||||
'GEOHASH' => $prefixFirst,
|
||||
'GEOPOS' => $prefixFirst,
|
||||
'GEODIST' => $prefixFirst,
|
||||
'GEORADIUS' => $prefixGeoradius,
|
||||
'GEORADIUSBYMEMBER' => $prefixGeoradius,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -197,7 +209,7 @@ class KeyPrefixProcessor implements ProcessorInterface
|
||||
if ($command instanceof PrefixableCommandInterface) {
|
||||
$command->prefixKeys($this->prefix);
|
||||
} elseif (isset($this->commands[$commandID = strtoupper($command->getId())])) {
|
||||
call_user_func($this->commands[$commandID], $command, $this->prefix);
|
||||
$this->commands[$commandID]($command, $this->prefix);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Redis\AbstractCommand;
|
||||
use Predis\Command\Command as RedisCommand;
|
||||
use Predis\Command\Traits\Keys;
|
||||
|
||||
abstract class BZPOPBase extends RedisCommand
|
||||
{
|
||||
use Keys {
|
||||
Keys::setArguments as setKeys;
|
||||
}
|
||||
|
||||
protected static $keysArgumentPositionOffset = 0;
|
||||
|
||||
abstract public function getId(): string;
|
||||
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$this->setKeys($arguments, false);
|
||||
}
|
||||
|
||||
public function parseResponse($data)
|
||||
{
|
||||
$key = array_shift($data);
|
||||
|
||||
if (null === $key) {
|
||||
return [$key];
|
||||
}
|
||||
|
||||
return array_combine([$key], [[$data[0] => $data[1]]]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
class BLMOVE extends LMOVE
|
||||
{
|
||||
public function getId()
|
||||
{
|
||||
return 'BLMOVE';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
class BLMPOP extends LMPOP
|
||||
{
|
||||
protected static $keysArgumentPositionOffset = 1;
|
||||
protected static $leftRightArgumentPositionOffset = 2;
|
||||
protected static $countArgumentPositionOffset = 3;
|
||||
|
||||
public function getId()
|
||||
{
|
||||
return 'BLMPOP';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
/**
|
||||
* @link https://redis.io/commands/bzmpop/
|
||||
*
|
||||
* BZMPOP is the blocking variant of ZMPOP.
|
||||
*/
|
||||
class BZMPOP extends ZMPOP
|
||||
{
|
||||
protected static $keysArgumentPositionOffset = 1;
|
||||
protected static $countArgumentPositionOffset = 3;
|
||||
protected static $modifierArgumentPositionOffset = 2;
|
||||
|
||||
public function getId()
|
||||
{
|
||||
return 'BZMPOP';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Command\Redis\AbstractCommand\BZPOPBase;
|
||||
|
||||
/**
|
||||
* @link https://redis.io/commands/bzpopmax/
|
||||
*
|
||||
* BZPOPMAX is the blocking variant of the sorted set ZPOPMAX primitive.
|
||||
*
|
||||
* It is the blocking version because it blocks the connection when there are
|
||||
* no members to pop from any of the given sorted sets.
|
||||
* A member with the highest score is popped from first sorted set that is non-empty,
|
||||
* with the given keys being checked in the order that they are given.
|
||||
*/
|
||||
class BZPOPMAX extends BZPOPBase
|
||||
{
|
||||
public function getId(): string
|
||||
{
|
||||
return 'BZPOPMAX';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Command\Redis\AbstractCommand\BZPOPBase;
|
||||
|
||||
/**
|
||||
* @link https://redis.io/commands/bzpopmin/
|
||||
*
|
||||
* BZPOPMIN is the blocking variant of the sorted set ZPOPMIN primitive.
|
||||
*
|
||||
* It is the blocking version because it blocks the connection when there are
|
||||
* no members to pop from any of the given sorted sets.
|
||||
* A member with the lowest score is popped from first sorted set that is non-empty,
|
||||
* with the given keys being checked in the order that they are given.
|
||||
*/
|
||||
class BZPOPMIN extends BZPOPBase
|
||||
{
|
||||
public function getId(): string
|
||||
{
|
||||
return 'BZPOPMIN';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
use Predis\Command\Command as RedisCommand;
|
||||
use Predis\Command\Traits\DB;
|
||||
use Predis\Command\Traits\Replace;
|
||||
|
||||
/**
|
||||
* @link https://redis.io/commands/copy/
|
||||
*
|
||||
* This command copies the value stored at the source key to the destination key.
|
||||
*/
|
||||
class COPY extends RedisCommand
|
||||
{
|
||||
use DB {
|
||||
DB::setArguments as setDB;
|
||||
}
|
||||
use Replace {
|
||||
Replace::setArguments as setReplace;
|
||||
}
|
||||
|
||||
protected static $dbArgumentPositionOffset = 2;
|
||||
|
||||
public function getId()
|
||||
{
|
||||
return 'COPY';
|
||||
}
|
||||
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$this->setDB($arguments);
|
||||
$arguments = $this->getArguments();
|
||||
|
||||
$this->setReplace($arguments);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Command\Command as RedisCommand;
|
||||
use Predis\Command\Traits\Timeout;
|
||||
use Predis\Command\Traits\To\ServerTo;
|
||||
|
||||
class FAILOVER extends RedisCommand
|
||||
{
|
||||
use ServerTo {
|
||||
ServerTo::setArguments as setTo;
|
||||
}
|
||||
use Timeout {
|
||||
Timeout::setArguments as setTimeout;
|
||||
}
|
||||
|
||||
protected static $toArgumentPositionOffset = 0;
|
||||
protected static $timeoutArgumentPositionOffset = 2;
|
||||
|
||||
public function getId()
|
||||
{
|
||||
return 'FAILOVER';
|
||||
}
|
||||
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
if (array_key_exists(1, $arguments) && false !== $arguments[1]) {
|
||||
$arguments[1] = 'ABORT';
|
||||
}
|
||||
|
||||
$this->setTimeout($arguments);
|
||||
$arguments = $this->getArguments();
|
||||
|
||||
$this->setTo($arguments);
|
||||
$this->filterArguments();
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,11 @@ namespace Predis\Command\Redis;
|
||||
use Predis\Command\Command as RedisCommand;
|
||||
|
||||
/**
|
||||
* @deprecated As of Redis version 6.2.0, this command is regarded as deprecated.
|
||||
*
|
||||
* It can be replaced by GEOSEARCH and GEOSEARCHSTORE with the BYRADIUS argument
|
||||
* when migrating or writing new code.
|
||||
*
|
||||
* @link http://redis.io/commands/georadius
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
|
||||
@@ -12,6 +12,11 @@
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
/**
|
||||
* @deprecated As of Redis version 6.2.0, this command is regarded as deprecated.
|
||||
*
|
||||
* It can be replaced by GEOSEARCH and GEOSEARCHSTORE with the FROMMEMBER arguments
|
||||
* when migrating or writing new code.
|
||||
*
|
||||
* @link http://redis.io/commands/georadiusbymember
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Command\Command as RedisCommand;
|
||||
use Predis\Command\Traits\By\GeoBy;
|
||||
use Predis\Command\Traits\Count;
|
||||
use Predis\Command\Traits\From\GeoFrom;
|
||||
use Predis\Command\Traits\Sorting;
|
||||
use Predis\Command\Traits\With\WithCoord;
|
||||
use Predis\Command\Traits\With\WithDist;
|
||||
use Predis\Command\Traits\With\WithHash;
|
||||
|
||||
/**
|
||||
* @link https://redis.io/commands/geosearch/
|
||||
*
|
||||
* Return the members of a sorted set populated with geospatial information using GEOADD,
|
||||
* which are within the borders of the area specified by a given shape.
|
||||
*
|
||||
* This command extends the GEORADIUS command, so in addition to searching
|
||||
* within circular areas, it supports searching within rectangular areas.
|
||||
*/
|
||||
class GEOSEARCH extends RedisCommand
|
||||
{
|
||||
use GeoFrom {
|
||||
GeoFrom::setArguments as setFrom;
|
||||
}
|
||||
use GeoBy {
|
||||
GeoBy::setArguments as setBy;
|
||||
}
|
||||
use Sorting {
|
||||
Sorting::setArguments as setSorting;
|
||||
}
|
||||
use Count {
|
||||
Count::setArguments as setCount;
|
||||
}
|
||||
use WithCoord {
|
||||
WithCoord::setArguments as setWithCoord;
|
||||
}
|
||||
use WithDist {
|
||||
WithDist::setArguments as setWithDist;
|
||||
}
|
||||
use WithHash {
|
||||
WithHash::setArguments as setWithHash;
|
||||
}
|
||||
|
||||
protected static $sortArgumentPositionOffset = 3;
|
||||
protected static $countArgumentPositionOffset = 4;
|
||||
protected static $withCoordArgumentPositionOffset = 6;
|
||||
protected static $withDistArgumentPositionOffset = 7;
|
||||
protected static $withHashArgumentPositionOffset = 8;
|
||||
|
||||
public function getId()
|
||||
{
|
||||
return 'GEOSEARCH';
|
||||
}
|
||||
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$this->setSorting($arguments);
|
||||
$arguments = $this->getArguments();
|
||||
|
||||
$this->setWithCoord($arguments);
|
||||
$arguments = $this->getArguments();
|
||||
|
||||
$this->setWithDist($arguments);
|
||||
$arguments = $this->getArguments();
|
||||
|
||||
$this->setWithHash($arguments);
|
||||
$arguments = $this->getArguments();
|
||||
|
||||
$this->setCount($arguments, $arguments[5] ?? false);
|
||||
$arguments = $this->getArguments();
|
||||
|
||||
$this->setFrom($arguments);
|
||||
$arguments = $this->getArguments();
|
||||
|
||||
$this->setBy($arguments);
|
||||
$this->filterArguments();
|
||||
}
|
||||
|
||||
public function parseResponse($data)
|
||||
{
|
||||
$parsedData = [];
|
||||
$itemKey = '';
|
||||
|
||||
foreach ($data as $item) {
|
||||
if (!is_array($item)) {
|
||||
$parsedData[] = $item;
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($item as $key => $itemRow) {
|
||||
if ($key === 0) {
|
||||
$itemKey = $itemRow;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_string($itemRow)) {
|
||||
$parsedData[$itemKey]['dist'] = round((float)$itemRow, 5);
|
||||
} elseif (is_int($itemRow)) {
|
||||
$parsedData[$itemKey]['hash'] = $itemRow;
|
||||
} else {
|
||||
$parsedData[$itemKey]['lng'] = round($itemRow[0], 5);
|
||||
$parsedData[$itemKey]['lat'] = round($itemRow[1], 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $parsedData;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Command\Command as RedisCommand;
|
||||
use Predis\Command\Traits\By\GeoBy;
|
||||
use Predis\Command\Traits\Count;
|
||||
use Predis\Command\Traits\From\GeoFrom;
|
||||
use Predis\Command\Traits\Sorting;
|
||||
use Predis\Command\Traits\Storedist;
|
||||
|
||||
/**
|
||||
* @link https://redis.io/commands/geosearchstore/
|
||||
*
|
||||
* This command is like GEOSEARCH, but stores the result in destination key.
|
||||
*/
|
||||
class GEOSEARCHSTORE extends RedisCommand
|
||||
{
|
||||
use GeoFrom {
|
||||
GeoFrom::setArguments as setFrom;
|
||||
}
|
||||
use GeoBy {
|
||||
GeoBy::setArguments as setBy;
|
||||
}
|
||||
use Sorting {
|
||||
Sorting::setArguments as setSorting;
|
||||
}
|
||||
use Count {
|
||||
Count::setArguments as setCount;
|
||||
}
|
||||
use Storedist {
|
||||
Storedist::setArguments as setStoreDist;
|
||||
}
|
||||
|
||||
protected static $sortArgumentPositionOffset = 4;
|
||||
protected static $countArgumentPositionOffset = 5;
|
||||
protected static $storeDistArgumentPositionOffset = 7;
|
||||
|
||||
public function getId()
|
||||
{
|
||||
return 'GEOSEARCHSTORE';
|
||||
}
|
||||
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$this->setStoreDist($arguments);
|
||||
$arguments = $this->getArguments();
|
||||
|
||||
$this->setCount($arguments, $arguments[6] ?? false);
|
||||
$arguments = $this->getArguments();
|
||||
|
||||
$this->setSorting($arguments);
|
||||
$arguments = $this->getArguments();
|
||||
|
||||
$this->setFrom($arguments);
|
||||
$arguments = $this->getArguments();
|
||||
|
||||
$this->setBy($arguments);
|
||||
$this->filterArguments();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Command\Command as RedisCommand;
|
||||
|
||||
class GETDEL extends RedisCommand
|
||||
{
|
||||
public function getId()
|
||||
{
|
||||
return 'GETDEL';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Command\Command as RedisCommand;
|
||||
use UnexpectedValueException;
|
||||
|
||||
class GETEX extends RedisCommand
|
||||
{
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
private static $modifierEnum = [
|
||||
'ex' => 'EX',
|
||||
'px' => 'PX',
|
||||
'exat' => 'EXAT',
|
||||
'pxat' => 'PXAT',
|
||||
'persist' => 'PERSIST',
|
||||
];
|
||||
|
||||
public function getId()
|
||||
{
|
||||
return 'GETEX';
|
||||
}
|
||||
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
if (!array_key_exists(1, $arguments) || $arguments[1] === '') {
|
||||
parent::setArguments([$arguments[0]]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!in_array(strtoupper($arguments[1]), self::$modifierEnum)) {
|
||||
$enumValues = implode(', ', array_keys(self::$modifierEnum));
|
||||
throw new UnexpectedValueException("Modifier argument accepts only: {$enumValues} values");
|
||||
}
|
||||
|
||||
if ($arguments[1] === 'persist') {
|
||||
parent::setArguments([$arguments[0], self::$modifierEnum[$arguments[1]]]);
|
||||
return;
|
||||
}
|
||||
|
||||
$arguments[1] = self::$modifierEnum[$arguments[1]];
|
||||
|
||||
if (!array_key_exists(2, $arguments)) {
|
||||
throw new UnexpectedValueException('You should provide value for current modifier');
|
||||
}
|
||||
|
||||
parent::setArguments($arguments);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Command\Command as RedisCommand;
|
||||
use Predis\Command\Traits\With\WithValues;
|
||||
|
||||
/**
|
||||
* @link https://redis.io/commands/hrandfield/
|
||||
*
|
||||
* When called with just the key argument, return a random field from the hash value stored at key.
|
||||
*
|
||||
* If the provided count argument is positive, return an array of distinct fields.
|
||||
* The array's length is either count or the hash's number of fields (HLEN), whichever is lower.
|
||||
*/
|
||||
class HRANDFIELD extends RedisCommand
|
||||
{
|
||||
use WithValues;
|
||||
|
||||
public function getId()
|
||||
{
|
||||
return 'HRANDFIELD';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Command\Command as RedisCommand;
|
||||
|
||||
class LMOVE extends RedisCommand
|
||||
{
|
||||
public function getId()
|
||||
{
|
||||
return 'LMOVE';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Command\Command as RedisCommand;
|
||||
use Predis\Command\Traits\Count;
|
||||
use \Predis\Command\Traits\Keys;
|
||||
use Predis\Command\Traits\LeftRight;
|
||||
|
||||
class LMPOP extends RedisCommand
|
||||
{
|
||||
use Keys {
|
||||
Keys::setArguments as setKeys;
|
||||
}
|
||||
use LeftRight {
|
||||
LeftRight::setArguments as setLeftRight;
|
||||
}
|
||||
use Count {
|
||||
Count::setArguments as setCount;
|
||||
}
|
||||
|
||||
protected static $keysArgumentPositionOffset = 0;
|
||||
protected static $leftRightArgumentPositionOffset = 1;
|
||||
protected static $countArgumentPositionOffset = 2;
|
||||
|
||||
public function getId()
|
||||
{
|
||||
return 'LMPOP';
|
||||
}
|
||||
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$this->setCount($arguments);
|
||||
$arguments = $this->getArguments();
|
||||
|
||||
$this->setLeftRight($arguments);
|
||||
$arguments = $this->getArguments();
|
||||
|
||||
$this->setKeys($arguments);
|
||||
$this->filterArguments();
|
||||
}
|
||||
|
||||
public function parseResponse($data)
|
||||
{
|
||||
if (null !== $data) {
|
||||
return [$data[0] => $data[1]];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Command\Command as RedisCommand;
|
||||
|
||||
/**
|
||||
* @link https://redis.io/commands/smismember/
|
||||
*
|
||||
* Returns whether each member is a member of the set stored at key.
|
||||
*/
|
||||
class SMISMEMBER extends RedisCommand
|
||||
{
|
||||
public function getId()
|
||||
{
|
||||
return 'SMISMEMBER';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Command\Command as RedisCommand;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/xadd
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class XADD extends RedisCommand
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'XADD';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$args = array();
|
||||
|
||||
$args[] = $arguments[0];
|
||||
$options = $arguments[3] ?? [];
|
||||
|
||||
if (isset($options['nomkstream']) && $options['nomkstream']) {
|
||||
$args[] = 'NOMKSTREAM';
|
||||
}
|
||||
|
||||
if (isset($options['trim']) && is_array($options['trim'])) {
|
||||
array_push($args, ...$options['trim']);
|
||||
|
||||
if (isset($options['limit'])) {
|
||||
$args[] = 'LIMIT';
|
||||
$args[] = $options['limit'];
|
||||
}
|
||||
}
|
||||
|
||||
// ID, default to * to let Redis set it
|
||||
$args[] = $arguments[2] ?? '*';
|
||||
if (isset($arguments[1]) && is_array($arguments[1])) {
|
||||
foreach ($arguments[1] as $key => $val) {
|
||||
$args[] = $key;
|
||||
$args[] = $val;
|
||||
}
|
||||
}
|
||||
|
||||
parent::setArguments($args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Command\Command as RedisCommand;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/xdel
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class XDEL extends RedisCommand
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'XDEL';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$arguments = self::normalizeVariadic($arguments);
|
||||
|
||||
parent::setArguments($arguments);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Command\Command as RedisCommand;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/xlen
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class XLEN extends RedisCommand
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'XLEN';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Command\Command as RedisCommand;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/xrange
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class XRANGE extends RedisCommand
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'XRANGE';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
if (count($arguments) === 4) {
|
||||
$arguments[] = $arguments[3];
|
||||
$arguments[3] = 'COUNT';
|
||||
}
|
||||
|
||||
parent::setArguments($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function parseResponse($data)
|
||||
{
|
||||
$result = array();
|
||||
foreach ($data as $entry) {
|
||||
$processed = array();
|
||||
$count = count($entry[1]);
|
||||
|
||||
for ($i = 0; $i < $count; ++$i) {
|
||||
$processed[$entry[1][$i]] = $entry[1][++$i];
|
||||
}
|
||||
|
||||
$result[$entry[0]] = $processed;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/xrevrange
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class XREVRANGE extends XRANGE
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'XREVRANGE';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Command\Command as RedisCommand;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/xtrim
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class XTRIM extends RedisCommand
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'XTRIM';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$args = [];
|
||||
$options = $arguments[3] ?? [];
|
||||
|
||||
$args[] = $arguments[0];
|
||||
// Either e.g. 'MAXLEN' or ['MAXLEN', '~']
|
||||
if (is_array($arguments[1])) {
|
||||
array_push($args, ...$arguments[1]);
|
||||
} else {
|
||||
$args[] = $arguments[1];
|
||||
}
|
||||
|
||||
$args[] = $arguments[2];
|
||||
if (isset($options['limit'])) {
|
||||
$args[] = 'LIMIT';
|
||||
$args[] = $options['limit'];
|
||||
}
|
||||
|
||||
parent::setArguments($args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Command\Command as RedisCommand;
|
||||
use Predis\Command\Traits\Keys;
|
||||
use Predis\Command\Traits\With\WithScores;
|
||||
|
||||
/**
|
||||
* @link https://redis.io/commands/zdiff/
|
||||
*
|
||||
* This command is similar to ZDIFFSTORE, but instead of
|
||||
* storing the resulting sorted set, it is returned to the client.
|
||||
*/
|
||||
class ZDIFF extends RedisCommand
|
||||
{
|
||||
use WithScores {
|
||||
WithScores::setArguments as setWithScore;
|
||||
}
|
||||
use Keys {
|
||||
Keys::setArguments as setKeys;
|
||||
}
|
||||
|
||||
protected static $keysArgumentPositionOffset = 0;
|
||||
|
||||
public function getId()
|
||||
{
|
||||
return 'ZDIFF';
|
||||
}
|
||||
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$this->setKeys($arguments);
|
||||
$arguments = $this->getArguments();
|
||||
|
||||
$this->setWithScore($arguments);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Command\Command as RedisCommand;
|
||||
use Predis\Command\Traits\Keys;
|
||||
|
||||
/**
|
||||
* @link https://redis.io/commands/zdiffstore/
|
||||
*
|
||||
* Computes the difference between the first and all successive input sorted sets
|
||||
* and stores the result in destination. The total number of input keys is specified by numkeys.
|
||||
*
|
||||
* Keys that do not exist are considered to be empty sets.
|
||||
*
|
||||
* If destination already exists, it is overwritten.
|
||||
*/
|
||||
class ZDIFFSTORE extends RedisCommand
|
||||
{
|
||||
use Keys {
|
||||
Keys::setArguments as setKeys;
|
||||
}
|
||||
|
||||
public static $keysArgumentPositionOffset = 1;
|
||||
|
||||
public function getId()
|
||||
{
|
||||
return 'ZDIFFSTORE';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Command\Traits\With\WithScores;
|
||||
|
||||
/**
|
||||
* @link https://redis.io/commands/zinter/
|
||||
*
|
||||
* This command is similar to ZINTERSTORE, but instead of
|
||||
* storing the resulting sorted set, it is returned to the client.
|
||||
*/
|
||||
class ZINTER extends ZINTERSTORE
|
||||
{
|
||||
use WithScores;
|
||||
|
||||
protected static $keysArgumentPositionOffset = 0;
|
||||
protected static $weightsArgumentPositionOffset = 1;
|
||||
protected static $aggregateArgumentPositionOffset = 2;
|
||||
|
||||
public function getId()
|
||||
{
|
||||
return 'ZINTER';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Command\Command as RedisCommand;
|
||||
use Predis\Command\Traits\Keys;
|
||||
use Predis\Command\Traits\Limit;
|
||||
|
||||
/**
|
||||
* @link https://redis.io/commands/zintercard/
|
||||
*
|
||||
* This command is similar to ZINTER, but instead of returning the result set,
|
||||
* it returns just the cardinality of the result.
|
||||
*/
|
||||
class ZINTERCARD extends RedisCommand
|
||||
{
|
||||
use Keys {
|
||||
Keys::setArguments as setKeys;
|
||||
}
|
||||
use Limit {
|
||||
Limit::setArguments as setLimit;
|
||||
}
|
||||
|
||||
protected static $keysArgumentPositionOffset = 0;
|
||||
protected static $limitArgumentPositionOffset = 1;
|
||||
|
||||
public function getId()
|
||||
{
|
||||
return 'ZINTERCARD';
|
||||
}
|
||||
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$this->setLimit($arguments);
|
||||
$arguments = $this->getArguments();
|
||||
|
||||
$this->setKeys($arguments);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Command\Command as RedisCommand;
|
||||
use Predis\Command\Traits\Count;
|
||||
use Predis\Command\Traits\MinMaxModifier;
|
||||
use Predis\Command\Traits\Keys;
|
||||
|
||||
/**
|
||||
* @link https://redis.io/commands/zmpop/
|
||||
*
|
||||
* Pops one or more elements, that are member-score pairs,
|
||||
* from the first non-empty sorted set in the provided list of key names.
|
||||
*/
|
||||
class ZMPOP extends RedisCommand
|
||||
{
|
||||
use Keys {
|
||||
Keys::setArguments as setKeys;
|
||||
}
|
||||
use Count {
|
||||
Count::setArguments as setCount;
|
||||
}
|
||||
use MinMaxModifier;
|
||||
|
||||
protected static $keysArgumentPositionOffset = 0;
|
||||
protected static $countArgumentPositionOffset = 2;
|
||||
protected static $modifierArgumentPositionOffset = 1;
|
||||
|
||||
public function getId()
|
||||
{
|
||||
return 'ZMPOP';
|
||||
}
|
||||
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$this->setCount($arguments);
|
||||
$arguments = $this->getArguments();
|
||||
|
||||
$this->resolveModifier(static::$modifierArgumentPositionOffset, $arguments);
|
||||
|
||||
$this->setKeys($arguments);
|
||||
$arguments = $this->getArguments();
|
||||
|
||||
parent::setArguments($arguments);
|
||||
}
|
||||
|
||||
public function parseResponse($data)
|
||||
{
|
||||
$key = array_shift($data);
|
||||
|
||||
if (null === $key) {
|
||||
return [$key];
|
||||
}
|
||||
|
||||
$data = $data[0];
|
||||
$parsedData = [];
|
||||
|
||||
for ($i = 0, $iMax = count($data); $i < $iMax; $i++) {
|
||||
for ($j = 0, $jMax = count($data[$i]); $j < $jMax; ++$j) {
|
||||
if ($data[$i][$j + 1] ?? false) {
|
||||
$parsedData[$data[$i][$j]] = $data[$i][++$j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array_combine([$key], [$parsedData]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Command\Command as RedisCommand;
|
||||
|
||||
/**
|
||||
* @link https://redis.io/commands/zmscore/
|
||||
*
|
||||
* Returns the scores associated with the specified members
|
||||
* in the sorted set stored at key.
|
||||
*
|
||||
* For every member that does not exist in the sorted set, a null value is returned.
|
||||
*
|
||||
*/
|
||||
class ZMSCORE extends RedisCommand
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'ZMSCORE';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Command\Command as RedisCommand;
|
||||
use Predis\Command\Traits\With\WithScores;
|
||||
|
||||
/**
|
||||
* @link https://redis.io/commands/zrandmember/
|
||||
*
|
||||
* Return a random element from the sorted set value stored at key.
|
||||
*
|
||||
* If the provided count argument is positive, return an array of distinct elements.
|
||||
*
|
||||
* If called with a negative count, the behavior changes and the command
|
||||
* is allowed to return the same element multiple times.
|
||||
*
|
||||
*/
|
||||
class ZRANDMEMBER extends RedisCommand
|
||||
{
|
||||
use WithScores;
|
||||
|
||||
public function getId()
|
||||
{
|
||||
return 'ZRANDMEMBER';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Command\Command as RedisCommand;
|
||||
use Predis\Command\Traits\By\ByLexByScore;
|
||||
use Predis\Command\Traits\Limit;
|
||||
use Predis\Command\Traits\Rev;
|
||||
|
||||
/**
|
||||
* @link https://redis.io/commands/zrangestore/
|
||||
*
|
||||
* This command is like ZRANGE, but stores the result in the destination key.
|
||||
*/
|
||||
class ZRANGESTORE extends RedisCommand
|
||||
{
|
||||
use ByLexByScore {
|
||||
ByLexByScore::setArguments as setByLexByScoreArgument;
|
||||
}
|
||||
use Rev {
|
||||
Rev::setArguments as setReversedArgument;
|
||||
}
|
||||
use Limit {
|
||||
Limit::setArguments as setLimitArguments;
|
||||
}
|
||||
|
||||
protected static $byLexByScoreArgumentPositionOffset = 4;
|
||||
protected static $revArgumentPositionOffset = 5;
|
||||
protected static $limitArgumentPositionOffset = 6;
|
||||
|
||||
public function getId()
|
||||
{
|
||||
return 'ZRANGESTORE';
|
||||
}
|
||||
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$this->setByLexByScoreArgument($arguments);
|
||||
$arguments = $this->getArguments();
|
||||
|
||||
$this->setReversedArgument($arguments);
|
||||
$arguments = $this->getArguments();
|
||||
|
||||
$this->setLimitArguments($arguments);
|
||||
$this->filterArguments();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Command\Traits\With\WithScores;
|
||||
|
||||
/**
|
||||
* @link https://redis.io/commands/zunion/
|
||||
*
|
||||
* This command is similar to ZUNIONSTORE, but instead of
|
||||
* storing the resulting sorted set, it is returned to the client.
|
||||
*/
|
||||
class ZUNION extends ZUNIONSTORE
|
||||
{
|
||||
use WithScores;
|
||||
|
||||
protected static $keysArgumentPositionOffset = 0;
|
||||
protected static $weightsArgumentPositionOffset = 1;
|
||||
protected static $aggregateArgumentPositionOffset = 2;
|
||||
|
||||
public function getId()
|
||||
{
|
||||
return 'ZUNION';
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,9 @@
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Command\Command as RedisCommand;
|
||||
use Predis\Command\Traits\Aggregate;
|
||||
use Predis\Command\Traits\Keys;
|
||||
use Predis\Command\Traits\Weights;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/zunionstore
|
||||
@@ -20,6 +23,20 @@ use Predis\Command\Command as RedisCommand;
|
||||
*/
|
||||
class ZUNIONSTORE extends RedisCommand
|
||||
{
|
||||
use Keys {
|
||||
Keys::setArguments as setKeys;
|
||||
}
|
||||
use Weights {
|
||||
Weights::setArguments as setWeights;
|
||||
}
|
||||
use Aggregate{
|
||||
Aggregate::setArguments as setAggregate;
|
||||
}
|
||||
|
||||
protected static $keysArgumentPositionOffset = 1;
|
||||
protected static $weightsArgumentPositionOffset = 2;
|
||||
protected static $aggregateArgumentPositionOffset = 3;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@@ -33,48 +50,19 @@ class ZUNIONSTORE extends RedisCommand
|
||||
*/
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$options = array();
|
||||
$argc = count($arguments);
|
||||
|
||||
if ($argc > 2 && is_array($arguments[$argc - 1])) {
|
||||
$options = $this->prepareOptions(array_pop($arguments));
|
||||
// support old `$options` array for backwards compatibility
|
||||
if (! isset($arguments[3]) && (isset($arguments[2]['weights']) || isset($arguments[2]['aggregate']))) {
|
||||
$options = array_pop($arguments);
|
||||
array_push($arguments, $options['weights'] ?? []);
|
||||
array_push($arguments, $options['aggregate'] ?? 'sum');
|
||||
}
|
||||
|
||||
if (is_array($arguments[1])) {
|
||||
$arguments = array_merge(
|
||||
array($arguments[0], count($arguments[1])),
|
||||
$arguments[1]
|
||||
);
|
||||
}
|
||||
$this->setAggregate($arguments);
|
||||
$arguments = $this->getArguments();
|
||||
|
||||
parent::setArguments(array_merge($arguments, $options));
|
||||
}
|
||||
$this->setWeights($arguments);
|
||||
$arguments = $this->getArguments();
|
||||
|
||||
/**
|
||||
* Returns a list of options and modifiers compatible with Redis.
|
||||
*
|
||||
* @param array $options List of options.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function prepareOptions($options)
|
||||
{
|
||||
$opts = array_change_key_case($options, CASE_UPPER);
|
||||
$finalizedOpts = array();
|
||||
|
||||
if (isset($opts['WEIGHTS']) && is_array($opts['WEIGHTS'])) {
|
||||
$finalizedOpts[] = 'WEIGHTS';
|
||||
|
||||
foreach ($opts['WEIGHTS'] as $weight) {
|
||||
$finalizedOpts[] = $weight;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($opts['AGGREGATE'])) {
|
||||
$finalizedOpts[] = 'AGGREGATE';
|
||||
$finalizedOpts[] = $opts['AGGREGATE'];
|
||||
}
|
||||
|
||||
return $finalizedOpts;
|
||||
$this->setKeys($arguments);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Traits;
|
||||
|
||||
use Predis\Command\Command;
|
||||
use UnexpectedValueException;
|
||||
|
||||
/**
|
||||
* @mixin Command
|
||||
*/
|
||||
trait Aggregate
|
||||
{
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
private static $aggregateValuesEnum = [
|
||||
'min' => 'MIN',
|
||||
'max' => 'MAX',
|
||||
'sum' => 'SUM'
|
||||
];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private static $aggregateModifier = 'AGGREGATE';
|
||||
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$argumentsLength = count($arguments);
|
||||
|
||||
if (static::$aggregateArgumentPositionOffset >= $argumentsLength) {
|
||||
parent::setArguments($arguments);
|
||||
return;
|
||||
}
|
||||
|
||||
$argument = $arguments[static::$aggregateArgumentPositionOffset];
|
||||
|
||||
if (is_string($argument) && in_array(strtoupper($argument), self::$aggregateValuesEnum)) {
|
||||
$argument = self::$aggregateValuesEnum[$argument];
|
||||
} else {
|
||||
$enumValues = implode(', ', array_keys(self::$aggregateValuesEnum));
|
||||
throw new UnexpectedValueException("Aggregate argument accepts only: {$enumValues} values");
|
||||
}
|
||||
|
||||
$argumentsBefore = array_slice($arguments, 0, static::$aggregateArgumentPositionOffset);
|
||||
$argumentsAfter = array_slice($arguments, static::$aggregateArgumentPositionOffset + 1);
|
||||
|
||||
parent::setArguments(array_merge(
|
||||
$argumentsBefore,
|
||||
[self::$aggregateModifier],
|
||||
[$argument],
|
||||
$argumentsAfter
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Traits\By;
|
||||
|
||||
use Predis\Command\Command;
|
||||
use UnexpectedValueException;
|
||||
|
||||
/**
|
||||
* @mixin Command
|
||||
*/
|
||||
trait ByLexByScore
|
||||
{
|
||||
private static $argumentsEnum = [
|
||||
'bylex' => 'BYLEX',
|
||||
'byscore' => 'BYSCORE',
|
||||
];
|
||||
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$argument = $arguments[static::$byLexByScoreArgumentPositionOffset];
|
||||
|
||||
if (false === $argument) {
|
||||
parent::setArguments($arguments);
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_string($argument) && in_array(strtoupper($argument), self::$argumentsEnum)) {
|
||||
$argument = self::$argumentsEnum[$argument];
|
||||
} else {
|
||||
throw new UnexpectedValueException("By argument accepts only \"bylex\" and \"byscore\" values");
|
||||
}
|
||||
|
||||
$argumentsBefore = array_slice($arguments, 0, static::$byLexByScoreArgumentPositionOffset);
|
||||
$argumentsAfter = array_slice($arguments, static::$byLexByScoreArgumentPositionOffset + 1);
|
||||
|
||||
parent::setArguments(array_merge($argumentsBefore, [$argument], $argumentsAfter));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Traits\By;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Predis\Command\Argument\Geospatial\ByInterface;
|
||||
|
||||
trait GeoBy
|
||||
{
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$argumentPositionOffset = $this->getByArgumentPositionOffset($arguments);
|
||||
|
||||
if (null === $argumentPositionOffset) {
|
||||
throw new InvalidArgumentException('Invalid BY argument value given');
|
||||
}
|
||||
|
||||
$byArgumentObject = $arguments[$argumentPositionOffset];
|
||||
$argumentsBefore = array_slice($arguments, 0, $argumentPositionOffset);
|
||||
$argumentsAfter = array_slice($arguments, $argumentPositionOffset + 1);
|
||||
|
||||
parent::setArguments(array_merge(
|
||||
$argumentsBefore,
|
||||
$byArgumentObject->toArray(),
|
||||
$argumentsAfter
|
||||
));
|
||||
}
|
||||
|
||||
private function getByArgumentPositionOffset(array $arguments): ?int
|
||||
{
|
||||
foreach ($arguments as $i => $value) {
|
||||
if ($value instanceof ByInterface) {
|
||||
return $i;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Traits;
|
||||
|
||||
use Predis\Command\Command;
|
||||
use UnexpectedValueException;
|
||||
|
||||
/**
|
||||
* @mixin Command
|
||||
*/
|
||||
trait Count
|
||||
{
|
||||
private $countModifier = 'COUNT';
|
||||
private $anyModifier = 'ANY';
|
||||
|
||||
public function setArguments(array $arguments, bool $any = false)
|
||||
{
|
||||
$argumentsLength = count($arguments);
|
||||
|
||||
if (static::$countArgumentPositionOffset >= $argumentsLength) {
|
||||
parent::setArguments($arguments);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($arguments[static::$countArgumentPositionOffset] === -1) {
|
||||
array_splice($arguments, static::$countArgumentPositionOffset, 1, [false]);
|
||||
parent::setArguments($arguments);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($arguments[static::$countArgumentPositionOffset] < 1) {
|
||||
throw new UnexpectedValueException('Wrong count argument value or position offset');
|
||||
}
|
||||
|
||||
$countArgument = $arguments[static::$countArgumentPositionOffset];
|
||||
$argumentsBefore = array_slice($arguments, 0, static::$countArgumentPositionOffset);
|
||||
$argumentsAfter = array_slice($arguments, static::$countArgumentPositionOffset + 2);
|
||||
|
||||
if (!$any) {
|
||||
$argumentsAfter = array_slice($arguments, static::$countArgumentPositionOffset + 1);
|
||||
parent::setArguments(array_merge(
|
||||
$argumentsBefore,
|
||||
[$this->countModifier],
|
||||
[$countArgument],
|
||||
$argumentsAfter
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
parent::setArguments(array_merge(
|
||||
$argumentsBefore,
|
||||
[$this->countModifier],
|
||||
[$countArgument],
|
||||
[$this->anyModifier],
|
||||
$argumentsAfter
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Traits;
|
||||
|
||||
use UnexpectedValueException;
|
||||
|
||||
trait DB
|
||||
{
|
||||
private $dbModifier = 'DB';
|
||||
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$argumentsLength = count($arguments);
|
||||
|
||||
if (static::$dbArgumentPositionOffset >= $argumentsLength) {
|
||||
parent::setArguments($arguments);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_numeric($arguments[static::$dbArgumentPositionOffset])) {
|
||||
throw new UnexpectedValueException('DB argument should be a valid numeric value');
|
||||
}
|
||||
|
||||
if ($arguments[static::$dbArgumentPositionOffset] < 0) {
|
||||
array_splice($arguments, static::$dbArgumentPositionOffset, 1);
|
||||
parent::setArguments($arguments);
|
||||
return;
|
||||
}
|
||||
|
||||
$argument = $arguments[static::$dbArgumentPositionOffset];
|
||||
$argumentsBefore = array_slice($arguments, 0, static::$dbArgumentPositionOffset);
|
||||
$argumentsAfter = array_slice($arguments, static::$dbArgumentPositionOffset + 1);
|
||||
|
||||
parent::setArguments(array_merge(
|
||||
$argumentsBefore,
|
||||
[$this->dbModifier],
|
||||
[$argument],
|
||||
$argumentsAfter
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Traits\From;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Predis\Command\Argument\Geospatial\FromInterface;
|
||||
|
||||
trait GeoFrom
|
||||
{
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$argumentPositionOffset = $this->getFromArgumentPositionOffset($arguments);
|
||||
|
||||
if (null === $argumentPositionOffset) {
|
||||
throw new InvalidArgumentException('Invalid FROM argument value given');
|
||||
}
|
||||
|
||||
$fromArgumentObject = $arguments[$argumentPositionOffset];
|
||||
$argumentsBefore = array_slice($arguments, 0, $argumentPositionOffset);
|
||||
$argumentsAfter = array_slice($arguments, $argumentPositionOffset + 1);
|
||||
|
||||
parent::setArguments(array_merge(
|
||||
$argumentsBefore,
|
||||
$fromArgumentObject->toArray(),
|
||||
$argumentsAfter
|
||||
));
|
||||
}
|
||||
|
||||
private function getFromArgumentPositionOffset(array $arguments): ?int
|
||||
{
|
||||
foreach ($arguments as $i => $value) {
|
||||
if ($value instanceof FromInterface) {
|
||||
return $i;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Traits;
|
||||
|
||||
use Predis\Command\Command;
|
||||
use UnexpectedValueException;
|
||||
|
||||
/**
|
||||
* @mixin Command
|
||||
*/
|
||||
trait Keys
|
||||
{
|
||||
public function setArguments(array $arguments, bool $withNumkeys = true)
|
||||
{
|
||||
$argumentsLength = count($arguments);
|
||||
|
||||
if (
|
||||
static::$keysArgumentPositionOffset > $argumentsLength ||
|
||||
!is_array($arguments[static::$keysArgumentPositionOffset])
|
||||
) {
|
||||
throw new UnexpectedValueException('Wrong keys argument type or position offset');
|
||||
}
|
||||
|
||||
$keysArgument = $arguments[static::$keysArgumentPositionOffset];
|
||||
$argumentsBeforeKeys = array_slice($arguments, 0, static::$keysArgumentPositionOffset);
|
||||
$argumentsAfterKeys = array_slice($arguments, static::$keysArgumentPositionOffset + 1);
|
||||
|
||||
if ($withNumkeys) {
|
||||
$numkeys = count($keysArgument);
|
||||
parent::setArguments(array_merge($argumentsBeforeKeys, [$numkeys], $keysArgument, $argumentsAfterKeys));
|
||||
return;
|
||||
}
|
||||
|
||||
parent::setArguments(array_merge($argumentsBeforeKeys, $keysArgument, $argumentsAfterKeys));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Traits;
|
||||
|
||||
use Predis\Command\Command;
|
||||
use UnexpectedValueException;
|
||||
|
||||
/**
|
||||
* @mixin Command
|
||||
*/
|
||||
trait LeftRight
|
||||
{
|
||||
/**
|
||||
* @var array{string: string}
|
||||
*/
|
||||
private static $leftRightEnum = [
|
||||
'left' => 'LEFT',
|
||||
'right' => 'RIGHT',
|
||||
];
|
||||
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$argumentsLength = count($arguments);
|
||||
|
||||
if (static::$leftRightArgumentPositionOffset >= $argumentsLength) {
|
||||
$arguments[] = 'LEFT';
|
||||
parent::setArguments($arguments);
|
||||
return;
|
||||
}
|
||||
|
||||
$argument = $arguments[static::$leftRightArgumentPositionOffset];
|
||||
|
||||
if (is_string($argument) && in_array(strtoupper($argument), self::$leftRightEnum, true)) {
|
||||
$argument = self::$leftRightEnum[$argument];
|
||||
} else {
|
||||
$enumValues = implode(', ', array_keys(self::$leftRightEnum));
|
||||
throw new UnexpectedValueException("Left/Right argument accepts only: {$enumValues} values");
|
||||
}
|
||||
|
||||
$argumentsBefore = array_slice($arguments, 0, static::$leftRightArgumentPositionOffset);
|
||||
$argumentsAfter = array_slice($arguments, static::$leftRightArgumentPositionOffset + 1);
|
||||
|
||||
parent::setArguments(array_merge(
|
||||
$argumentsBefore,
|
||||
[$argument],
|
||||
$argumentsAfter
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Traits;
|
||||
|
||||
use Predis\Command\Command;
|
||||
use UnexpectedValueException;
|
||||
|
||||
/**
|
||||
* @mixin Command
|
||||
*/
|
||||
trait Limit
|
||||
{
|
||||
private static $limitModifier = 'LIMIT';
|
||||
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$argumentsLength = count($arguments);
|
||||
$argumentsBefore = array_slice($arguments, 0, static::$limitArgumentPositionOffset);
|
||||
|
||||
if (
|
||||
static::$limitArgumentPositionOffset >= $argumentsLength
|
||||
|| false === $arguments[static::$limitArgumentPositionOffset]
|
||||
) {
|
||||
parent::setArguments($argumentsBefore);
|
||||
return;
|
||||
}
|
||||
|
||||
$argument = $arguments[static::$limitArgumentPositionOffset];
|
||||
$argumentsAfter = array_slice($arguments, static::$limitArgumentPositionOffset + 1);
|
||||
|
||||
if (true === $argument) {
|
||||
parent::setArguments(array_merge($argumentsBefore, [self::$limitModifier], $argumentsAfter));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_int($argument)) {
|
||||
throw new UnexpectedValueException('Wrong limit argument type');
|
||||
}
|
||||
|
||||
parent::setArguments(array_merge($argumentsBefore, [self::$limitModifier], [$argument], $argumentsAfter));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Traits;
|
||||
|
||||
use Predis\Command\Command;
|
||||
use UnexpectedValueException;
|
||||
|
||||
/**
|
||||
* @mixin Command
|
||||
*/
|
||||
trait MinMaxModifier
|
||||
{
|
||||
/**
|
||||
* @var array{string: string}
|
||||
*/
|
||||
private $modifierEnum = [
|
||||
'min' => 'MIN',
|
||||
'max' => 'MAX',
|
||||
];
|
||||
|
||||
public function resolveModifier(int $offset, array &$arguments): void
|
||||
{
|
||||
if ($offset >= count($arguments)) {
|
||||
$arguments[$offset] = $this->modifierEnum['min'];
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_string($arguments[$offset]) || !array_key_exists($arguments[$offset], $this->modifierEnum)) {
|
||||
throw new UnexpectedValueException('Wrong type of modifier given');
|
||||
}
|
||||
|
||||
$arguments[$offset] = $this->modifierEnum[$arguments[$offset]];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Traits;
|
||||
|
||||
use Predis\Command\Command;
|
||||
|
||||
/**
|
||||
* @mixin Command
|
||||
*/
|
||||
trait Replace
|
||||
{
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$replace = array_pop($arguments);
|
||||
|
||||
if (is_bool($replace) && $replace) {
|
||||
$arguments[] = 'REPLACE';
|
||||
} else if (!is_bool($replace)) {
|
||||
$arguments[] = $replace;
|
||||
}
|
||||
|
||||
parent::setArguments($arguments);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Traits;
|
||||
|
||||
use Predis\Command\Command;
|
||||
use UnexpectedValueException;
|
||||
|
||||
/**
|
||||
* @mixin Command
|
||||
*/
|
||||
trait Rev
|
||||
{
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$argument = $arguments[static::$revArgumentPositionOffset];
|
||||
|
||||
if (false === $argument) {
|
||||
parent::setArguments($arguments);
|
||||
return;
|
||||
}
|
||||
|
||||
if (true === $argument) {
|
||||
$argument = 'REV';
|
||||
} else {
|
||||
throw new UnexpectedValueException('Wrong rev argument type');
|
||||
}
|
||||
|
||||
$argumentsBefore = array_slice($arguments, 0, static::$revArgumentPositionOffset);
|
||||
$argumentsAfter = array_slice($arguments, static::$revArgumentPositionOffset + 1);
|
||||
|
||||
parent::setArguments(array_merge($argumentsBefore, [$argument], $argumentsAfter));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Traits;
|
||||
|
||||
use UnexpectedValueException;
|
||||
|
||||
trait Sorting
|
||||
{
|
||||
private static $sortingEnum = [
|
||||
'asc' => 'ASC',
|
||||
'desc' => 'DESC',
|
||||
];
|
||||
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$argumentsLength = count($arguments);
|
||||
|
||||
if (static::$sortArgumentPositionOffset >= $argumentsLength) {
|
||||
parent::setArguments($arguments);
|
||||
return;
|
||||
}
|
||||
|
||||
$argument = $arguments[static::$sortArgumentPositionOffset];
|
||||
|
||||
if (null === $argument) {
|
||||
array_splice($arguments, static::$sortArgumentPositionOffset, 1, [false]);
|
||||
parent::setArguments($arguments);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!in_array(strtoupper($argument), self::$sortingEnum, true)) {
|
||||
$enumValues = implode(', ', array_keys(self::$sortingEnum));
|
||||
throw new UnexpectedValueException("Sorting argument accepts only: {$enumValues} values");
|
||||
}
|
||||
|
||||
$argumentsBefore = array_slice($arguments, 0, static::$sortArgumentPositionOffset);
|
||||
$argumentsAfter = array_slice($arguments, static::$sortArgumentPositionOffset + 1);
|
||||
|
||||
parent::setArguments(array_merge(
|
||||
$argumentsBefore,
|
||||
[self::$sortingEnum[$argument]],
|
||||
$argumentsAfter
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Traits;
|
||||
|
||||
use Predis\Command\Command;
|
||||
use UnexpectedValueException;
|
||||
|
||||
/**
|
||||
* @mixin Command
|
||||
*/
|
||||
trait Storedist
|
||||
{
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$argumentsLength = count($arguments);
|
||||
|
||||
if (
|
||||
static::$storeDistArgumentPositionOffset >= $argumentsLength
|
||||
|| false === $arguments[static::$storeDistArgumentPositionOffset]
|
||||
) {
|
||||
parent::setArguments($arguments);
|
||||
return;
|
||||
}
|
||||
|
||||
$argument = $arguments[static::$storeDistArgumentPositionOffset];
|
||||
|
||||
if (true === $argument) {
|
||||
$argument = 'STOREDIST';
|
||||
} else {
|
||||
throw new UnexpectedValueException("Wrong STOREDIST argument type");
|
||||
}
|
||||
|
||||
$argumentsBefore = array_slice($arguments, 0, static::$storeDistArgumentPositionOffset);
|
||||
$argumentsAfter = array_slice($arguments, static::$storeDistArgumentPositionOffset + 1);
|
||||
|
||||
parent::setArguments(array_merge($argumentsBefore, [$argument], $argumentsAfter));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Traits;
|
||||
|
||||
use UnexpectedValueException;
|
||||
|
||||
trait Timeout
|
||||
{
|
||||
private static $timeoutModifier = 'TIMEOUT';
|
||||
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$argumentsLength = count($arguments);
|
||||
|
||||
if (static::$timeoutArgumentPositionOffset >= $argumentsLength) {
|
||||
parent::setArguments($arguments);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($arguments[static::$timeoutArgumentPositionOffset] === -1) {
|
||||
array_splice($arguments, static::$timeoutArgumentPositionOffset, 1, [false]);
|
||||
parent::setArguments($arguments);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($arguments[static::$timeoutArgumentPositionOffset] < 1) {
|
||||
throw new UnexpectedValueException('Wrong timeout argument value or position offset');
|
||||
}
|
||||
|
||||
$argument = $arguments[static::$timeoutArgumentPositionOffset];
|
||||
$argumentsBefore = array_slice($arguments, 0, static::$timeoutArgumentPositionOffset);
|
||||
$argumentsAfter = array_slice($arguments, static::$timeoutArgumentPositionOffset + 1);
|
||||
|
||||
parent::setArguments(array_merge(
|
||||
$argumentsBefore,
|
||||
[self::$timeoutModifier],
|
||||
[$argument],
|
||||
$argumentsAfter
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Traits\To;
|
||||
|
||||
use Predis\Command\Argument\Server\To;
|
||||
|
||||
trait ServerTo
|
||||
{
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$argumentsLength = count($arguments);
|
||||
|
||||
if (static::$toArgumentPositionOffset >= $argumentsLength) {
|
||||
parent::setArguments($arguments);
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var To|null $toArgument */
|
||||
$toArgument = $arguments[static::$toArgumentPositionOffset];
|
||||
|
||||
if (null === $toArgument) {
|
||||
array_splice($arguments, static::$toArgumentPositionOffset, 1, [false]);
|
||||
parent::setArguments($arguments);
|
||||
return;
|
||||
}
|
||||
|
||||
$argumentsBefore = array_slice($arguments, 0, static::$toArgumentPositionOffset);
|
||||
$argumentsAfter = array_slice($arguments, static::$toArgumentPositionOffset + 1);
|
||||
|
||||
parent::setArguments(array_merge(
|
||||
$argumentsBefore,
|
||||
$toArgument->toArray(),
|
||||
$argumentsAfter
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Traits;
|
||||
|
||||
use Predis\Command\Command;
|
||||
use UnexpectedValueException;
|
||||
|
||||
/**
|
||||
* @mixin Command
|
||||
*/
|
||||
trait Weights
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private static $weightsModifier = 'WEIGHTS';
|
||||
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$argumentsLength = count($arguments);
|
||||
|
||||
if (static::$weightsArgumentPositionOffset >= $argumentsLength) {
|
||||
parent::setArguments($arguments);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_array($arguments[static::$weightsArgumentPositionOffset])) {
|
||||
throw new UnexpectedValueException('Wrong weights argument type');
|
||||
}
|
||||
|
||||
$weightsArray = $arguments[static::$weightsArgumentPositionOffset];
|
||||
|
||||
if (empty($weightsArray)) {
|
||||
unset($arguments[static::$weightsArgumentPositionOffset]);
|
||||
parent::setArguments($arguments);
|
||||
return;
|
||||
}
|
||||
|
||||
$argumentsBefore = array_slice($arguments, 0, static::$weightsArgumentPositionOffset);
|
||||
$argumentsAfter = array_slice($arguments, static::$weightsArgumentPositionOffset + 1);
|
||||
|
||||
parent::setArguments(array_merge(
|
||||
$argumentsBefore,
|
||||
[self::$weightsModifier],
|
||||
$weightsArray,
|
||||
$argumentsAfter
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Traits\With;
|
||||
|
||||
use Predis\Command\Command;
|
||||
use UnexpectedValueException;
|
||||
|
||||
/**
|
||||
* @mixin Command
|
||||
*/
|
||||
trait WithCoord
|
||||
{
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$argumentsLength = count($arguments);
|
||||
|
||||
if (
|
||||
static::$withCoordArgumentPositionOffset >= $argumentsLength
|
||||
|| false === $arguments[static::$withCoordArgumentPositionOffset]
|
||||
) {
|
||||
parent::setArguments($arguments);
|
||||
return;
|
||||
}
|
||||
|
||||
$argument = $arguments[static::$withCoordArgumentPositionOffset];
|
||||
|
||||
if (true === $argument) {
|
||||
$argument = 'WITHCOORD';
|
||||
} else {
|
||||
throw new UnexpectedValueException("Wrong WITHCOORD argument type");
|
||||
}
|
||||
|
||||
$argumentsBefore = array_slice($arguments, 0, static::$withCoordArgumentPositionOffset);
|
||||
$argumentsAfter = array_slice($arguments, static::$withCoordArgumentPositionOffset + 1);
|
||||
|
||||
parent::setArguments(array_merge($argumentsBefore, [$argument], $argumentsAfter));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Traits\With;
|
||||
|
||||
use UnexpectedValueException;
|
||||
|
||||
trait WithDist
|
||||
{
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$argumentsLength = count($arguments);
|
||||
|
||||
if (
|
||||
static::$withDistArgumentPositionOffset >= $argumentsLength
|
||||
|| false === $arguments[static::$withDistArgumentPositionOffset]
|
||||
) {
|
||||
parent::setArguments($arguments);
|
||||
return;
|
||||
}
|
||||
|
||||
$argument = $arguments[static::$withDistArgumentPositionOffset];
|
||||
|
||||
if (true === $argument) {
|
||||
$argument = 'WITHDIST';
|
||||
} else {
|
||||
throw new UnexpectedValueException("Wrong WITHDIST argument type");
|
||||
}
|
||||
|
||||
$argumentsBefore = array_slice($arguments, 0, static::$withDistArgumentPositionOffset);
|
||||
$argumentsAfter = array_slice($arguments, static::$withDistArgumentPositionOffset + 1);
|
||||
|
||||
parent::setArguments(array_merge($argumentsBefore, [$argument], $argumentsAfter));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Traits\With;
|
||||
|
||||
use UnexpectedValueException;
|
||||
|
||||
trait WithHash
|
||||
{
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$argumentsLength = count($arguments);
|
||||
|
||||
if (
|
||||
static::$withHashArgumentPositionOffset >= $argumentsLength
|
||||
|| false === $arguments[static::$withHashArgumentPositionOffset]
|
||||
) {
|
||||
parent::setArguments($arguments);
|
||||
return;
|
||||
}
|
||||
|
||||
$argument = $arguments[static::$withHashArgumentPositionOffset];
|
||||
|
||||
if (true === $argument) {
|
||||
$argument = 'WITHHASH';
|
||||
} else {
|
||||
throw new UnexpectedValueException("Wrong WITHHASH argument type");
|
||||
}
|
||||
|
||||
$argumentsBefore = array_slice($arguments, 0, static::$withHashArgumentPositionOffset);
|
||||
$argumentsAfter = array_slice($arguments, static::$withHashArgumentPositionOffset + 1);
|
||||
|
||||
parent::setArguments(array_merge($argumentsBefore, [$argument], $argumentsAfter));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Traits\With;
|
||||
|
||||
use Predis\Command\Command;
|
||||
|
||||
/**
|
||||
* Handles last argument passed into command as WITHSCORES
|
||||
*
|
||||
* @mixin Command
|
||||
*/
|
||||
trait WithScores
|
||||
{
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$withScores = array_pop($arguments);
|
||||
|
||||
if (is_bool($withScores) && $withScores) {
|
||||
$arguments[] = 'WITHSCORES';
|
||||
} else if (!is_bool($withScores)) {
|
||||
$arguments[] = $withScores;
|
||||
}
|
||||
|
||||
parent::setArguments($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for the presence of the WITHSCORES modifier.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function isWithScoreModifier(): bool
|
||||
{
|
||||
$arguments = parent::getArguments();
|
||||
$lastArgument = (!empty($arguments)) ? $arguments[count($arguments) - 1] : null;
|
||||
|
||||
return is_string($lastArgument) && strtoupper($lastArgument) === 'WITHSCORES';
|
||||
}
|
||||
|
||||
public function parseResponse($data)
|
||||
{
|
||||
if ($this->isWithScoreModifier()) {
|
||||
$result = [];
|
||||
|
||||
for ($i = 0, $iMax = count($data); $i < $iMax; ++$i) {
|
||||
if ($data[$i + 1] ?? false) {
|
||||
$result[$data[$i]] = $data[++$i];
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Traits\With;
|
||||
|
||||
use Predis\Command\Command;
|
||||
|
||||
/**
|
||||
* @mixin Command
|
||||
*/
|
||||
trait WithValues
|
||||
{
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$withValues = array_pop($arguments);
|
||||
|
||||
if (is_bool($withValues) && $withValues) {
|
||||
$arguments[] = 'WITHVALUES';
|
||||
} else if (!is_bool($withValues)) {
|
||||
$arguments[] = $withValues;
|
||||
}
|
||||
|
||||
parent::setArguments($arguments);
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,8 @@ use Predis\Connection\FactoryInterface;
|
||||
use Predis\Connection\NodeConnectionInterface;
|
||||
use Predis\NotSupportedException;
|
||||
use Predis\Response\ErrorInterface as ErrorResponseInterface;
|
||||
use Predis\Response\ServerException;
|
||||
use Predis\Response\Error as ErrorResponse;
|
||||
|
||||
/**
|
||||
* Abstraction for a Redis-backed cluster of nodes (Redis >= 3.0.0).
|
||||
@@ -54,6 +56,7 @@ class RedisCluster implements ClusterInterface, \IteratorAggregate, \Countable
|
||||
private $strategy;
|
||||
private $connections;
|
||||
private $retryLimit = 5;
|
||||
private $retryInterval = 10;
|
||||
|
||||
/**
|
||||
* @param FactoryInterface $connections Optional connection factory.
|
||||
@@ -82,6 +85,26 @@ class RedisCluster implements ClusterInterface, \IteratorAggregate, \Countable
|
||||
$this->retryLimit = (int) $retry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the initial retry interval (milliseconds).
|
||||
*
|
||||
* @param int $retryInterval Milliseconds between retries.
|
||||
*/
|
||||
public function setRetryInterval($retryInterval)
|
||||
{
|
||||
$this->retryInterval = (int) $retryInterval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the retry interval (milliseconds).
|
||||
*
|
||||
* @return int Milliseconds between retries.
|
||||
*/
|
||||
public function getRetryInterval()
|
||||
{
|
||||
return (int) $this->retryInterval;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@@ -207,6 +230,7 @@ class RedisCluster implements ClusterInterface, \IteratorAggregate, \Countable
|
||||
private function queryClusterNodeForSlotMap(NodeConnectionInterface $connection)
|
||||
{
|
||||
$retries = 0;
|
||||
$retryAfter = $this->retryInterval;
|
||||
$command = RawCommand::create('CLUSTER', 'SLOTS');
|
||||
|
||||
RETRY_COMMAND: {
|
||||
@@ -226,7 +250,10 @@ class RedisCluster implements ClusterInterface, \IteratorAggregate, \Countable
|
||||
throw new ClientException('No connections left in the pool for `CLUSTER SLOTS`');
|
||||
}
|
||||
|
||||
usleep($retryAfter * 1000);
|
||||
$retryAfter = $retryAfter * 2;
|
||||
++$retries;
|
||||
|
||||
goto RETRY_COMMAND;
|
||||
}
|
||||
}
|
||||
@@ -482,24 +509,40 @@ class RedisCluster implements ClusterInterface, \IteratorAggregate, \Countable
|
||||
*/
|
||||
private function retryCommandOnFailure(CommandInterface $command, $method)
|
||||
{
|
||||
$failure = false;
|
||||
$retries = 0;
|
||||
$retryAfter = $this->retryInterval;
|
||||
|
||||
RETRY_COMMAND: {
|
||||
try {
|
||||
$response = $this->getConnectionByCommand($command)->$method($command);
|
||||
} catch (ConnectionException $exception) {
|
||||
$connection = $exception->getConnection();
|
||||
$connection->disconnect();
|
||||
|
||||
$this->remove($connection);
|
||||
if ($response instanceof ErrorResponse) {
|
||||
$message = $response->getMessage();
|
||||
|
||||
if ($failure) {
|
||||
if (strpos($message, 'CLUSTERDOWN') !== false) {
|
||||
throw new ServerException($message);
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $exception) {
|
||||
usleep($retryAfter * 1000);
|
||||
$retryAfter = $retryAfter * 2;
|
||||
|
||||
if ($exception instanceof ConnectionException) {
|
||||
$connection = $exception->getConnection();
|
||||
|
||||
if ($connection) {
|
||||
$connection->disconnect();
|
||||
$this->remove($connection);
|
||||
}
|
||||
}
|
||||
|
||||
if ($retries === $this->retryLimit) {
|
||||
throw $exception;
|
||||
} elseif ($this->useClusterSlots) {
|
||||
$this->askSlotMap();
|
||||
}
|
||||
|
||||
$failure = true;
|
||||
++$retries;
|
||||
|
||||
goto RETRY_COMMAND;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,14 @@ class Parameters implements ParametersInterface
|
||||
'port' => 6379,
|
||||
);
|
||||
|
||||
/**
|
||||
* Set of connection paramaters already filtered
|
||||
* for NULL or 0-length string values.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $parameters;
|
||||
|
||||
/**
|
||||
* @param array $parameters Named array of connection parameters.
|
||||
*/
|
||||
|
||||
@@ -70,6 +70,11 @@ class SentinelReplication implements ReplicationInterface
|
||||
*/
|
||||
protected $sentinels = array();
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $sentinelIndex = 0;
|
||||
|
||||
/**
|
||||
* @var NodeConnectionInterface
|
||||
*/
|
||||
@@ -264,6 +269,12 @@ class SentinelReplication implements ReplicationInterface
|
||||
$parameters['database'] = null;
|
||||
$parameters['username'] = null;
|
||||
|
||||
// don't leak password from between configurations
|
||||
// https://github.com/predis/predis/pull/807/#discussion_r985764770
|
||||
if (! isset($parameters['password'])) {
|
||||
$parameters['password'] = null;
|
||||
}
|
||||
|
||||
if (!isset($parameters['timeout'])) {
|
||||
$parameters['timeout'] = $this->sentinelTimeout;
|
||||
}
|
||||
@@ -282,11 +293,13 @@ class SentinelReplication implements ReplicationInterface
|
||||
public function getSentinelConnection()
|
||||
{
|
||||
if (!$this->sentinelConnection) {
|
||||
if (!$this->sentinels) {
|
||||
if ($this->sentinelIndex >= count($this->sentinels)) {
|
||||
$this->sentinelIndex = 0;
|
||||
throw new \Predis\ClientException('No sentinel server available for autodiscovery.');
|
||||
}
|
||||
|
||||
$sentinel = array_shift($this->sentinels);
|
||||
$sentinel = $this->sentinels[$this->sentinelIndex];
|
||||
++$this->sentinelIndex;
|
||||
$this->sentinelConnection = $this->createSentinelConnection($sentinel);
|
||||
}
|
||||
|
||||
@@ -307,6 +320,7 @@ class SentinelReplication implements ReplicationInterface
|
||||
);
|
||||
|
||||
$this->sentinels = array();
|
||||
$this->sentinelIndex = 0;
|
||||
// NOTE: sentinel server does not return itself, so we add it back.
|
||||
$this->sentinels[] = $sentinel->getParameters()->toArray();
|
||||
|
||||
|
||||
@@ -260,7 +260,7 @@ class StreamConnection extends AbstractConnection
|
||||
$socket = $this->getResource();
|
||||
|
||||
while (($length = strlen($buffer)) > 0) {
|
||||
$written = @fwrite($socket, $buffer);
|
||||
$written = is_resource($socket) ? @fwrite($socket, $buffer) : false;
|
||||
|
||||
if ($length === $written) {
|
||||
return;
|
||||
@@ -304,7 +304,7 @@ class StreamConnection extends AbstractConnection
|
||||
$bytesLeft = ($size += 2);
|
||||
|
||||
do {
|
||||
$chunk = fread($socket, min($bytesLeft, 4096));
|
||||
$chunk = is_resource($socket) ? fread($socket, min($bytesLeft, 4096)) : false;
|
||||
|
||||
if ($chunk === false || $chunk === '') {
|
||||
$this->onConnectionError('Error while reading bytes from the server.');
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace PHPUnit;
|
||||
|
||||
use PHPUnit\Framework\Constraint\Constraint;
|
||||
|
||||
class OneOfConstraint extends Constraint
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $array;
|
||||
|
||||
public function __construct(array $array)
|
||||
{
|
||||
$this->array = $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $other
|
||||
* @return bool
|
||||
*/
|
||||
protected function matches($other): bool
|
||||
{
|
||||
if (is_array($other)) {
|
||||
return !empty(array_intersect($other, $this->array));
|
||||
}
|
||||
|
||||
if (in_array($other, $this->array, true)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $other
|
||||
* @return string
|
||||
*/
|
||||
protected function failureDescription($other): string
|
||||
{
|
||||
return $this->toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function toString(): string
|
||||
{
|
||||
return 'given value matches any values from array';
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,6 @@ abstract class PredisCommandTestCase extends PredisTestCase
|
||||
* Returns a new client instance.
|
||||
*
|
||||
* @param bool $flushdb Flush selected database before returning the client
|
||||
*
|
||||
* @return Client
|
||||
*/
|
||||
public function getClient(bool $flushdb = true): Client
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
*/
|
||||
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\OneOfConstraint;
|
||||
use PHPUnit\Util\Test as TestUtil;
|
||||
use Predis\Client;
|
||||
use Predis\Command;
|
||||
use Predis\Connection;
|
||||
@@ -93,6 +95,19 @@ abstract class PredisTestCase extends \PHPUnit\Framework\TestCase
|
||||
$this->assertThat($actual, new ArrayHasSameValuesConstraint($expected), $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that actual value is one of the values from expected array.
|
||||
*
|
||||
* @param mixed $expected Expected array.
|
||||
* @param mixed $actual Actual value. If array given searching for any matching value between two arrays.
|
||||
* @param string $message Optional assertion message
|
||||
* @return void
|
||||
*/
|
||||
public function assertOneOf(array $expected, $actual, string $message = ''): void
|
||||
{
|
||||
$this->assertThat($actual, new OneOfConstraint($expected), $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a string matches a given regular expression.
|
||||
*
|
||||
@@ -315,7 +330,10 @@ abstract class PredisTestCase extends \PHPUnit\Framework\TestCase
|
||||
*/
|
||||
protected function getRequiredRedisServerVersion(): ?string
|
||||
{
|
||||
$annotations = $this->getAnnotations();
|
||||
$annotations = TestUtil::parseTestMethodAnnotations(
|
||||
get_class($this),
|
||||
$this->getName(false)
|
||||
);
|
||||
|
||||
if (isset($annotations['method']['requiresRedisVersion'], $annotations['method']['group']) &&
|
||||
!empty($annotations['method']['requiresRedisVersion']) &&
|
||||
|
||||
@@ -148,7 +148,7 @@ class PredisStrategyTest extends PredisTestCase
|
||||
{
|
||||
$strategy = $this->getClusterStrategy();
|
||||
$commands = $this->getCommandFactory();
|
||||
$arguments = array('{key}:destination', 2, '{key}:1', '{key}:1', array('aggregate' => 'SUM'));
|
||||
$arguments = array('{key}:destination', ['{key}:1', '{key}:1'], [], 'sum');
|
||||
|
||||
foreach ($this->getExpectedCommands('keys-zaggregated') as $commandID) {
|
||||
$command = $commands->create($commandID, $arguments);
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Redis\AbstractCommand;
|
||||
|
||||
use Predis\Command\CommandInterface;
|
||||
use PredisTestCase;
|
||||
|
||||
class BZPOPBaseTest extends PredisTestCase
|
||||
{
|
||||
/**
|
||||
* @var CommandInterface
|
||||
*/
|
||||
private $testCommand;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->testCommand = new class extends BZPOPBase {
|
||||
|
||||
public function getId(): string
|
||||
{
|
||||
return 'test';
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
* @dataProvider argumentsProvider
|
||||
*/
|
||||
public function testFilterArguments(array $actualArguments, array $expectedArguments): void
|
||||
{
|
||||
$this->testCommand->setArguments($actualArguments);
|
||||
|
||||
$this->assertSame($expectedArguments, $this->testCommand->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
* @dataProvider responsesProvider
|
||||
*/
|
||||
public function testParseResponse(array $actualResponse, array $expectedResponse): void
|
||||
{
|
||||
$this->assertSame($expectedResponse, $this->testCommand->parseResponse($actualResponse));
|
||||
}
|
||||
|
||||
public function argumentsProvider(): array
|
||||
{
|
||||
return [
|
||||
'with one key' => [
|
||||
[['key1'], 1],
|
||||
['key1', 1]
|
||||
],
|
||||
'with multiple keys' => [
|
||||
[['key1', 'key2', 'key3'], 1],
|
||||
['key1', 'key2', 'key3', 1]
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function responsesProvider(): array
|
||||
{
|
||||
return [
|
||||
'null-element array' => [
|
||||
[null],
|
||||
[null]
|
||||
],
|
||||
'three-element array' => [
|
||||
['key', 'member', 'score'],
|
||||
['key' => ['member' => 'score']]
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Response\ServerException;
|
||||
|
||||
class BLMOVE_Test extends PredisCommandTestCase
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function getExpectedCommand(): string
|
||||
{
|
||||
return BLMOVE::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function getExpectedId(): string
|
||||
{
|
||||
return 'BLMOVE';
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testFilterArguments(): void
|
||||
{
|
||||
$arguments = ['list', 'argument1', 'argument2', 'argument3'];
|
||||
$expected = ['list', 'argument1', 'argument2', 'argument3'];
|
||||
|
||||
$command = $this->getCommand();
|
||||
$command->setArguments($arguments);
|
||||
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testParseResponse(): void
|
||||
{
|
||||
$this->assertSame(1, $this->getCommand()->parseResponse(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @dataProvider listsProvider
|
||||
* @param array $firstList
|
||||
* @param array $secondList
|
||||
* @param string $where
|
||||
* @param string $to
|
||||
* @param string $expectedResponse
|
||||
* @param array $expectedModifiedFirstList
|
||||
* @param array $expectedModifiedSecondList
|
||||
* @return void
|
||||
* @requiresRedisVersion >= 6.2.0
|
||||
*/
|
||||
public function testReturnsCorrectListElement(
|
||||
array $firstList,
|
||||
array $secondList,
|
||||
string $where,
|
||||
string $to,
|
||||
string $expectedResponse,
|
||||
array $expectedModifiedFirstList,
|
||||
array $expectedModifiedSecondList
|
||||
): void {
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->rpush('test-blmove1', $firstList);
|
||||
$redis->rpush('test-blmove2', $secondList);
|
||||
|
||||
$actualResponse = $redis->blmove('test-blmove1', 'test-blmove2', $where, $to, 0);
|
||||
|
||||
$this->assertSame($expectedResponse, $actualResponse);
|
||||
$this->assertSame($expectedModifiedFirstList, $redis->lrange('test-blmove1', 0, -1));
|
||||
$this->assertSame($expectedModifiedSecondList, $redis->lrange('test-blmove2', 0, -1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @dataProvider sameListProvider
|
||||
* @param array $list
|
||||
* @param string $where
|
||||
* @param string $to
|
||||
* @param string $expectedResponse
|
||||
* @param array $expectedModifiedList
|
||||
* @return void
|
||||
* @requiresRedisVersion >= 6.2.0
|
||||
*/
|
||||
public function testReturnsCorrectListElementAndListRotationPerformedOnTheSameListOperation(
|
||||
array $list,
|
||||
string $where,
|
||||
string $to,
|
||||
string $expectedResponse,
|
||||
array $expectedModifiedList
|
||||
): void {
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->rpush('test-blmove1', $list);
|
||||
|
||||
$actualResponse = $redis->blmove('test-blmove1', 'test-blmove1', $where, $to, 0);
|
||||
|
||||
$this->assertSame($expectedResponse, $actualResponse);
|
||||
$this->assertSame($expectedModifiedList, $redis->lrange('test-blmove1', 0, -1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @return void
|
||||
* @requiresRedisVersion >= 6.2.0
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType(): void
|
||||
{
|
||||
$this->expectException(ServerException::class);
|
||||
$this->expectExceptionMessage('Operation against a key holding the wrong kind of value');
|
||||
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->set('foo', 'bar');
|
||||
$redis->blmove('foo', 'test-lmove', 'LEFT', 'LEFT', 0);
|
||||
}
|
||||
|
||||
public function listsProvider(): array
|
||||
{
|
||||
return [
|
||||
'move first element from list into head of another list' => [
|
||||
['element1', 'element2', 'element3'],
|
||||
['element4', 'element5', 'element6'],
|
||||
'LEFT',
|
||||
'LEFT',
|
||||
'element1',
|
||||
['element2', 'element3'],
|
||||
['element1', 'element4', 'element5', 'element6'],
|
||||
],
|
||||
'move first element from list into tail of another list' => [
|
||||
['element1', 'element2', 'element3'],
|
||||
['element4', 'element5', 'element6'],
|
||||
'LEFT',
|
||||
'RIGHT',
|
||||
'element1',
|
||||
['element2', 'element3'],
|
||||
['element4', 'element5', 'element6', 'element1'],
|
||||
],
|
||||
'move last element from list into head of another list' => [
|
||||
['element1', 'element2', 'element3'],
|
||||
['element4', 'element5', 'element6'],
|
||||
'RIGHT',
|
||||
'LEFT',
|
||||
'element3',
|
||||
['element1', 'element2'],
|
||||
['element3', 'element4', 'element5', 'element6'],
|
||||
],
|
||||
'move last element from list into tail of another list' => [
|
||||
['element1', 'element2', 'element3'],
|
||||
['element4', 'element5', 'element6'],
|
||||
'RIGHT',
|
||||
'RIGHT',
|
||||
'element3',
|
||||
['element1', 'element2'],
|
||||
['element4', 'element5', 'element6', 'element3'],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function sameListProvider(): array
|
||||
{
|
||||
return [
|
||||
'list rotation - head into tail' => [
|
||||
['element1', 'element2', 'element3'],
|
||||
'LEFT',
|
||||
'RIGHT',
|
||||
'element1',
|
||||
['element2', 'element3', 'element1'],
|
||||
],
|
||||
'list rotation - tail into head' => [
|
||||
['element1', 'element2', 'element3'],
|
||||
'RIGHT',
|
||||
'LEFT',
|
||||
'element3',
|
||||
['element3', 'element1', 'element2'],
|
||||
],
|
||||
'list rotation - head into head' => [
|
||||
['element1', 'element2', 'element3'],
|
||||
'LEFT',
|
||||
'LEFT',
|
||||
'element1',
|
||||
['element1', 'element2', 'element3'],
|
||||
],
|
||||
'list rotation - tail into tail' => [
|
||||
['element1', 'element2', 'element3'],
|
||||
'RIGHT',
|
||||
'RIGHT',
|
||||
'element3',
|
||||
['element1', 'element2', 'element3'],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
/**
|
||||
* @group commands
|
||||
* @group realm-list
|
||||
*/
|
||||
class BLMPOP_Test extends PredisCommandTestCase
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCommand(): string
|
||||
{
|
||||
return BLMPOP::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedId(): string
|
||||
{
|
||||
return 'BLMPOP';
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
* @dataProvider argumentsProvider
|
||||
*/
|
||||
public function testFilterArguments(array $actualArguments, array $expectedArguments): void
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
$command->setArguments($actualArguments);
|
||||
|
||||
$this->assertSame($expectedArguments, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testParseResponse(): void
|
||||
{
|
||||
$raw = ['key', ['elem1', 'elem2']];
|
||||
$expected = ['key' => ['elem1', 'elem2']];
|
||||
|
||||
$command = $this->getCommand();
|
||||
|
||||
$this->assertSame($expected, $command->parseResponse($raw));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @dataProvider listProvider
|
||||
* @param int $timeout
|
||||
* @param array $listArguments
|
||||
* @param string $key
|
||||
* @param string $modifier
|
||||
* @param int $count
|
||||
* @param array $expectedResponse
|
||||
* @param array $expectedModifiedList
|
||||
* @return void
|
||||
* @requiresRedisVersion >= 7.0.0
|
||||
*/
|
||||
public function testPopElementsFromGivenList(
|
||||
int $timeout,
|
||||
array $listArguments,
|
||||
string $key,
|
||||
string $modifier,
|
||||
int $count,
|
||||
array $expectedResponse,
|
||||
array $expectedModifiedList
|
||||
): void {
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->lpush(...$listArguments);
|
||||
$actualResponse = $redis->blmpop($timeout, ['key1', $key], $modifier, $count);
|
||||
|
||||
$this->assertSame($expectedResponse, $actualResponse);
|
||||
$this->assertSame($expectedModifiedList, $redis->lrange($key, 0, -1));
|
||||
}
|
||||
|
||||
public function argumentsProvider(): array
|
||||
{
|
||||
return [
|
||||
'with default arguments' => [
|
||||
[1, ['key']],
|
||||
[1, 1, 'key', 'LEFT']
|
||||
],
|
||||
'with LEFT/RIGHT argument' => [
|
||||
[1, ['key'], 'right'],
|
||||
[1, 1, 'key', 'RIGHT']
|
||||
],
|
||||
'with COUNT argument' => [
|
||||
[1, ['key'], 'left', 2],
|
||||
[1, 1, 'key', 'LEFT', 'COUNT', 2]
|
||||
],
|
||||
'with all arguments' => [
|
||||
[1, ['key1', 'key2'], 'right', 2],
|
||||
[1, 2, 'key1', 'key2', 'RIGHT', 'COUNT', 2]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function listProvider(): array
|
||||
{
|
||||
return [
|
||||
'pops single element - left' => [
|
||||
1,
|
||||
['key', 'elem1', 'elem2', 'elem3'],
|
||||
'key',
|
||||
'left',
|
||||
1,
|
||||
['key' => ['elem3']],
|
||||
['elem2', 'elem1']
|
||||
],
|
||||
'pops single element - right' => [
|
||||
1,
|
||||
['key', 'elem1', 'elem2', 'elem3'],
|
||||
'key',
|
||||
'right',
|
||||
1,
|
||||
['key' => ['elem1']],
|
||||
['elem3', 'elem2']
|
||||
],
|
||||
'pops multiple elements' => [
|
||||
1,
|
||||
['key', 'elem1', 'elem2', 'elem3'],
|
||||
'key',
|
||||
'right',
|
||||
2,
|
||||
['key' => ['elem1', 'elem2']],
|
||||
['elem3'],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Response\ServerException;
|
||||
use UnexpectedValueException;
|
||||
|
||||
class BZMPOP_Test extends PredisCommandTestCase
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function getExpectedCommand(): string
|
||||
{
|
||||
return BZMPOP::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function getExpectedId(): string
|
||||
{
|
||||
return 'BZMPOP';
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
* @dataProvider argumentsProvider
|
||||
*/
|
||||
public function testFilterArguments(array $actualArguments, array $expectedArguments): void
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
$command->setArguments($actualArguments);
|
||||
|
||||
$this->assertSame($expectedArguments, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
* @dataProvider responsesProvider
|
||||
*/
|
||||
public function testParseResponse(array $actualResponse, array $expectedResponse): void
|
||||
{
|
||||
$this->assertSame($expectedResponse, $this->getCommand()->parseResponse($actualResponse));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @dataProvider sortedSetsProvider
|
||||
* @param int $timeout
|
||||
* @param array $sortedSetDictionary
|
||||
* @param string $key
|
||||
* @param string $modifier
|
||||
* @param int $count
|
||||
* @param array $expectedResponse
|
||||
* @param array $expectedModifiedSortedSet
|
||||
* @return void
|
||||
* @requiresRedisVersion >= 7.0
|
||||
*/
|
||||
public function testReturnsPoppedElementsFromGivenSortedSet(
|
||||
int $timeout,
|
||||
array $sortedSetDictionary,
|
||||
string $key,
|
||||
string $modifier,
|
||||
int $count,
|
||||
array $expectedResponse,
|
||||
array $expectedModifiedSortedSet
|
||||
): void {
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->zadd($key, ...$sortedSetDictionary);
|
||||
$actualResponse = $redis->bzmpop($timeout, [$key], $modifier, $count);
|
||||
|
||||
$this->assertSame($expectedResponse, $actualResponse);
|
||||
$this->assertSame($expectedModifiedSortedSet, $redis->zrange($key, 0, -1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @dataProvider unexpectedValuesProvider
|
||||
* @param int $timeout
|
||||
* @param array $keys
|
||||
* @param string $modifier
|
||||
* @param int $count
|
||||
* @param string $expectedExceptionMessage
|
||||
* @return void
|
||||
* @requiresRedisVersion >= 7.0
|
||||
*/
|
||||
public function testThrowsExceptionOnUnexpectedValueGiven(
|
||||
int $timeout,
|
||||
array $keys,
|
||||
string $modifier,
|
||||
int $count,
|
||||
string $expectedExceptionMessage
|
||||
): void {
|
||||
$redis = $this->getClient();
|
||||
|
||||
$this->expectException(UnexpectedValueException::class);
|
||||
$this->expectExceptionMessage($expectedExceptionMessage);
|
||||
|
||||
$redis->bzmpop($timeout, $keys, $modifier, $count);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @requiresRedisVersion >= 7.0
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType(): void
|
||||
{
|
||||
$this->expectException(ServerException::class);
|
||||
$this->expectExceptionMessage('Operation against a key holding the wrong kind of value');
|
||||
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->set('bzmpop_foo', 'bar');
|
||||
$redis->bzmpop(1, ['bzmpop_foo']);
|
||||
}
|
||||
|
||||
public function argumentsProvider(): array
|
||||
{
|
||||
return [
|
||||
'with one key' => [
|
||||
[10, ['key1'], 'min', 1],
|
||||
[10, 1, 'key1', 'MIN', 'COUNT', 1]
|
||||
],
|
||||
'with multiple keys' => [
|
||||
[10, ['key1', 'key2', 'key3'], 'max', 1],
|
||||
[10, 3, 'key1', 'key2', 'key3', 'MAX', 'COUNT', 1]
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function responsesProvider(): array
|
||||
{
|
||||
return [
|
||||
'null-element array' => [
|
||||
[null],
|
||||
[null]
|
||||
],
|
||||
'two-element array' => [
|
||||
['key', [['member1', 1, 'member2', 2, 'member3', 3]]],
|
||||
['key' => ['member1' => 1, 'member2' => 2, 'member3' => 3]]
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function sortedSetsProvider(): array
|
||||
{
|
||||
return [
|
||||
'with MIN modifier' => [
|
||||
1,
|
||||
[1, 'member1', 2, 'member2', 3, 'member3'],
|
||||
'test-bzmpop',
|
||||
'min',
|
||||
1,
|
||||
['test-bzmpop' => ['member1' => '1']],
|
||||
['member2', 'member3'],
|
||||
],
|
||||
'with MAX modifier' => [
|
||||
1,
|
||||
[1, 'member1', 2, 'member2', 3, 'member3'],
|
||||
'test-bzmpop',
|
||||
'max',
|
||||
1,
|
||||
['test-bzmpop' => ['member3' => '3']],
|
||||
['member1', 'member2'],
|
||||
],
|
||||
'with non-default COUNT' => [
|
||||
1,
|
||||
[1, 'member1', 2, 'member2', 3, 'member3'],
|
||||
'test-bzmpop',
|
||||
'max',
|
||||
2,
|
||||
['test-bzmpop' => ['member3' => '3', 'member2' => '2']],
|
||||
['member1'],
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function unexpectedValuesProvider(): array
|
||||
{
|
||||
return [
|
||||
'wrong modifier' => [
|
||||
1,
|
||||
['key1', 'key2'],
|
||||
'wrong modifier',
|
||||
1,
|
||||
'Wrong type of modifier given'
|
||||
],
|
||||
'wrong count' => [
|
||||
1,
|
||||
['key1', 'key2'],
|
||||
'min',
|
||||
0,
|
||||
'Wrong count argument value or position offset'
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Response\ServerException;
|
||||
use UnexpectedValueException;
|
||||
|
||||
class BZPOPMAX_Test extends PredisCommandTestCase
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function getExpectedCommand(): string
|
||||
{
|
||||
return BZPOPMAX::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function getExpectedId(): string
|
||||
{
|
||||
return 'BZPOPMAX';
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @return void
|
||||
* @requiresRedisVersion >= 5.0.0
|
||||
*/
|
||||
public function testReturnsPoppedMaxElementFromGivenNonEmptySortedSet(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
$sortedSetDictionary = [1, 'member1', 2, 'member2', 3, 'member3'];
|
||||
$expectedResponse = ['test-bzpopmax' => ['member3' => '3']];
|
||||
$expectedModifiedSortedSet = ['member1', 'member2'];
|
||||
|
||||
$redis->zadd('test-bzpopmax', ...$sortedSetDictionary);
|
||||
|
||||
$this->assertSame($expectedResponse, $redis->bzpopmax(['empty sorted set','test-bzpopmax'], 0));
|
||||
$this->assertSame($expectedModifiedSortedSet, $redis->zrange('test-bzpopmax', 0, -1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @return void
|
||||
* @requiresRedisVersion >= 5.0.0
|
||||
*/
|
||||
public function testThrowsExceptionOnUnexpectedValueGiven(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$this->expectException(UnexpectedValueException::class);
|
||||
$this->expectExceptionMessage('Wrong keys argument type or position offset');
|
||||
|
||||
$redis->bzpopmax(1, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @requiresRedisVersion >= 5.0.0
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType(): void
|
||||
{
|
||||
$this->expectException(ServerException::class);
|
||||
$this->expectExceptionMessage('Operation against a key holding the wrong kind of value');
|
||||
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->set('bzpopmax_foo', 'bar');
|
||||
$redis->bzpopmax(['bzpopmax_foo'], 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Response\ServerException;
|
||||
use UnexpectedValueException;
|
||||
|
||||
class BZPOPMIN_Test extends PredisCommandTestCase
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function getExpectedCommand(): string
|
||||
{
|
||||
return BZPOPMIN::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function getExpectedId(): string
|
||||
{
|
||||
return 'BZPOPMIN';
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @return void
|
||||
* @requiresRedisVersion >= 5.0.0
|
||||
*/
|
||||
public function testReturnsPoppedMinElementFromGivenNonEmptySortedSet(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
$sortedSetDictionary = [1, 'member1', 2, 'member2', 3, 'member3'];
|
||||
$expectedResponse = ['test-bzpopmin' => ['member1' => '1']];
|
||||
$expectedModifiedSortedSet = ['member2', 'member3'];
|
||||
|
||||
$redis->zadd('test-bzpopmin', ...$sortedSetDictionary);
|
||||
|
||||
$this->assertSame($expectedResponse, $redis->bzpopmin(['empty sorted set','test-bzpopmin'], 0));
|
||||
$this->assertSame($expectedModifiedSortedSet, $redis->zrange('test-bzpopmin', 0, -1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @return void
|
||||
* @requiresRedisVersion >= 5.0.0
|
||||
*/
|
||||
public function testThrowsExceptionOnUnexpectedValueGiven(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$this->expectException(UnexpectedValueException::class);
|
||||
$this->expectExceptionMessage('Wrong keys argument type or position offset');
|
||||
|
||||
$redis->bzpopmin(1, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @requiresRedisVersion >= 5.0.0
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType(): void
|
||||
{
|
||||
$this->expectException(ServerException::class);
|
||||
$this->expectExceptionMessage('Operation against a key holding the wrong kind of value');
|
||||
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->set('bzpopmin_foo', 'bar');
|
||||
$redis->bzpopmin(['bzpopmin_foo'], 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
class COPY_Test extends PredisCommandTestCase
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function getExpectedCommand(): string
|
||||
{
|
||||
return COPY::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function getExpectedId(): string
|
||||
{
|
||||
return 'COPY';
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
* @dataProvider argumentsProvider
|
||||
*/
|
||||
public function testFilterArguments(array $actualArguments, array $expectedArguments): void
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
$command->setArguments($actualArguments);
|
||||
|
||||
$this->assertSame($expectedArguments, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testParseResponse(): void
|
||||
{
|
||||
$this->assertSame(1, $this->getCommand()->parseResponse(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @return void
|
||||
* @requiresRedisVersion >= 6.2.0
|
||||
*/
|
||||
public function testSuccessfullyCopyValueOnNonExistingDestinationKey(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
$redis->set('key', 'value');
|
||||
|
||||
$actualResponse = $redis->copy('key', 'destination');
|
||||
|
||||
$this->assertSame(1, $actualResponse);
|
||||
$this->assertSame($redis->get('key'), $redis->get('destination'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @return void
|
||||
* @requiresRedisVersion >= 6.2.0
|
||||
*/
|
||||
public function testSuccessfullyCopyValueFromSourceToAnotherDb(): void
|
||||
{
|
||||
$defaultDatabaseIndexClient = $this->getClient();
|
||||
$defaultDatabaseIndexClient->set('key', 'value');
|
||||
|
||||
$copyResponse = $defaultDatabaseIndexClient->copy('key', 'new_key', 14);
|
||||
|
||||
$anotherDatabaseIndexClient = $this->createClient(['database' => 14], null, false);
|
||||
$actualValue = $anotherDatabaseIndexClient->get('new_key');
|
||||
$anotherDatabaseIndexClient->flushdb();
|
||||
|
||||
$this->assertNull($anotherDatabaseIndexClient->get('new_key'));
|
||||
$this->assertSame(1, $copyResponse);
|
||||
$this->assertSame('value', $actualValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @return void
|
||||
* @requiresRedisVersion >= 6.2.0
|
||||
*/
|
||||
public function testDoNotCopyValueOnAlreadyExistingDestinationKey(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
$redis->set('key', 'value');
|
||||
$redis->set('destination', 'destination_value');
|
||||
|
||||
$actualResponse = $redis->copy('key', 'destination');
|
||||
|
||||
$this->assertSame(0, $actualResponse);
|
||||
$this->assertSame('destination_value', $redis->get('destination'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @return void
|
||||
* @requiresRedisVersion >= 6.2.0
|
||||
*/
|
||||
public function testSuccessfullyCopyValueWithReplaceArgumentOnAlreadyExistingDestinationKey(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
$redis->set('key', 'value');
|
||||
$redis->set('destination', 'destination_value');
|
||||
|
||||
$actualResponse = $redis->copy('key', 'destination', -1, true);
|
||||
|
||||
$this->assertSame(1, $actualResponse);
|
||||
$this->assertSame('value', $redis->get('destination'));
|
||||
}
|
||||
|
||||
public function argumentsProvider(): array
|
||||
{
|
||||
return [
|
||||
'with default arguments' => [
|
||||
['source', 'destination'],
|
||||
['source', 'destination']
|
||||
],
|
||||
'with DB argument' => [
|
||||
['source', 'destination', 1],
|
||||
['source', 'destination', 'DB', 1]
|
||||
],
|
||||
'with replace argument' => [
|
||||
['source', 'destination', -1, true],
|
||||
['source', 'destination', 'REPLACE']
|
||||
],
|
||||
'with all arguments' => [
|
||||
['source', 'destination', 1, true],
|
||||
['source', 'destination', 'DB', 1, 'REPLACE']
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Command\Argument\Server\To;
|
||||
use UnexpectedValueException;
|
||||
|
||||
/**
|
||||
* @group commands
|
||||
* @group realm-server
|
||||
*/
|
||||
class FAILOVER_Test extends PredisCommandTestCase
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCommand(): string
|
||||
{
|
||||
return FAILOVER::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedId(): string
|
||||
{
|
||||
return 'FAILOVER';
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
* @dataProvider argumentsProvider
|
||||
*/
|
||||
public function testFilterArguments(array $actualArguments, array $expectedArguments): void
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
$command->setArguments($actualArguments);
|
||||
|
||||
$this->assertSameValues($expectedArguments, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testParseResponse(): void
|
||||
{
|
||||
$this->assertSame(1, $this->getCommand()->parseResponse(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @return void
|
||||
* @requiresRedisVersion >= 6.2.0
|
||||
*/
|
||||
public function testPerformFailoverOfConnectedReplica(): void
|
||||
{
|
||||
$this->markTestSkipped('Test requires configured replica node connected to master');
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @return void
|
||||
* @requiresRedisVersion >= 6.2.0
|
||||
*/
|
||||
public function testThrowsExceptionOnUnexpectedValueGiven(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
$this->expectException(UnexpectedValueException::class);
|
||||
$this->expectExceptionMessage('Wrong timeout argument value or position offset');
|
||||
|
||||
$redis->failover(null, false, 0);
|
||||
}
|
||||
|
||||
public function argumentsProvider(): array
|
||||
{
|
||||
return [
|
||||
'without optional arguments - no arguments' => [
|
||||
[],
|
||||
[]
|
||||
],
|
||||
'without optional arguments - default arguments' => [
|
||||
[null, false, -1],
|
||||
[]
|
||||
],
|
||||
'with TO argument - no FORCE' => [
|
||||
[new To('test', 9999)],
|
||||
['TO', 'test', 9999]
|
||||
],
|
||||
'with TO argument - with FORCE' => [
|
||||
[new To('test', 9999, true)],
|
||||
['TO', 'test', 9999, 'FORCE']
|
||||
],
|
||||
'with ABORT modifier' => [
|
||||
[null, true],
|
||||
['ABORT']
|
||||
],
|
||||
'with TIMEOUT argument' => [
|
||||
[null, false, 10],
|
||||
['TIMEOUT', 10]
|
||||
],
|
||||
'with all arguments' => [
|
||||
[new To('test', 9999, true), true, 10],
|
||||
['TO', 'test', 9999, 'FORCE', 'ABORT', 'TIMEOUT', 10]
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,354 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Predis\Command\Argument\Geospatial\ByBox;
|
||||
use Predis\Command\Argument\Geospatial\ByInterface;
|
||||
use Predis\Command\Argument\Geospatial\ByRadius;
|
||||
use Predis\Command\Argument\Geospatial\FromInterface;
|
||||
use Predis\Command\Argument\Geospatial\FromLonLat;
|
||||
use Predis\Command\Argument\Geospatial\FromMember;
|
||||
use UnexpectedValueException;
|
||||
|
||||
class GEOSEARCHSTORE_Test extends PredisCommandTestCase
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function getExpectedCommand(): string
|
||||
{
|
||||
return GEOSEARCHSTORE::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function getExpectedId(): string
|
||||
{
|
||||
return 'GEOSEARCHSTORE';
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
* @dataProvider argumentsProvider
|
||||
*/
|
||||
public function testFilterArguments(array $actualArguments, array $expectedArguments): void
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
$command->setArguments($actualArguments);
|
||||
|
||||
$this->assertSameValues($expectedArguments, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testParseResponse(): void
|
||||
{
|
||||
$this->assertSame(1, $this->getCommand()->parseResponse(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @dataProvider coordinatesProvider
|
||||
* @param array $firstCoordinates
|
||||
* @param array $secondCoordinates
|
||||
* @param array $thirdCoordinates
|
||||
* @param string $destination
|
||||
* @param string $source
|
||||
* @param FromInterface $from
|
||||
* @param ByInterface $by
|
||||
* @param string|null $sorting
|
||||
* @param int $count
|
||||
* @param bool $any
|
||||
* @param int $expectedResultingElements
|
||||
* @param array $expectedResponse
|
||||
* @return void
|
||||
* @requiresRedisVersion >= 6.2.0
|
||||
*/
|
||||
public function testStoresCorrectGivenGeospatialCoordinates(
|
||||
array $firstCoordinates,
|
||||
array $secondCoordinates,
|
||||
array $thirdCoordinates,
|
||||
string $destination,
|
||||
string $source,
|
||||
FromInterface $from,
|
||||
ByInterface $by,
|
||||
?string $sorting,
|
||||
int $count,
|
||||
bool $any,
|
||||
int $expectedResultingElements,
|
||||
array $expectedResponse
|
||||
): void {
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->geoadd(...$firstCoordinates);
|
||||
$redis->geoadd(...$secondCoordinates);
|
||||
$redis->geoadd(...$thirdCoordinates);
|
||||
|
||||
$actualResultingElements = $redis->geosearchstore(
|
||||
$destination,
|
||||
$source,
|
||||
$from,
|
||||
$by,
|
||||
$sorting,
|
||||
$count,
|
||||
$any
|
||||
);
|
||||
|
||||
$this->assertSame($expectedResultingElements, $actualResultingElements);
|
||||
$this->assertSame($expectedResponse, $redis->geosearch($destination, $from, $by, $sorting, $count, $any));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @return void
|
||||
* @requiresRedisVersion >= 6.2.0
|
||||
*/
|
||||
public function testStoresInSortedSetWithStoreDistArgumentProvided(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->geoadd('key', 1.1, 2, 'member1');
|
||||
$redis->geoadd('key', 2.1, 3, 'member2');
|
||||
$redis->geoadd('key', 3.1, 4, 'member3');
|
||||
|
||||
$actualResultingElements = $redis->geosearchstore(
|
||||
'destination',
|
||||
'key',
|
||||
new FromLonLat(1, 4),
|
||||
new ByRadius(9999, 'km'),
|
||||
null,
|
||||
2,
|
||||
false,
|
||||
true
|
||||
);
|
||||
|
||||
$this->assertSame(2, $actualResultingElements);
|
||||
$this->assertSame(['member2', 'member1'], $redis->zrange('destination', 0, -1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @dataProvider unexpectedValuesProvider
|
||||
* @param array $arguments
|
||||
* @param string $expectedException
|
||||
* @param string $expectedExceptionMessage
|
||||
* @return void
|
||||
* @requiresRedisVersion >= 6.2.0
|
||||
*/
|
||||
public function testThrowsExceptionOnUnexpectedValueProvided(
|
||||
array $arguments,
|
||||
string $expectedException,
|
||||
string $expectedExceptionMessage
|
||||
): void {
|
||||
$redis = $this->getClient();
|
||||
|
||||
$this->expectException($expectedException);
|
||||
$this->expectExceptionMessage($expectedExceptionMessage);
|
||||
|
||||
$redis->geosearchstore(...$arguments);
|
||||
}
|
||||
|
||||
public function argumentsProvider(): array
|
||||
{
|
||||
return [
|
||||
'with default arguments - FROMLONLAT, BYRADIUS' => [
|
||||
['destination', 'source', new FromLonLat(1.1, 2.2), new ByRadius(1, 'km')],
|
||||
['destination', 'source', 'FROMLONLAT', 1.1, 2.2, 'BYRADIUS', 1, 'km']
|
||||
],
|
||||
'with default arguments - FROMMEMBER, BYBOX' => [
|
||||
['destination', 'source', new FromMember('member'), new ByBox(1,1, 'km')],
|
||||
['destination', 'source', 'FROMMEMBER', 'member', 'BYBOX', 1, 1, 'km']
|
||||
],
|
||||
'with ASC sorting' => [
|
||||
['destination', 'source', new FromLonLat(1.1, 2.2), new ByRadius(1, 'km'), 'asc'],
|
||||
['destination', 'source', 'FROMLONLAT', 1.1, 2.2, 'BYRADIUS', 1, 'km', 'ASC']
|
||||
],
|
||||
'with DESC sorting' => [
|
||||
['destination', 'source', new FromLonLat(1.1, 2.2), new ByRadius(1, 'km'), 'desc'],
|
||||
['destination', 'source', 'FROMLONLAT', 1.1, 2.2, 'BYRADIUS', 1, 'km', 'DESC']
|
||||
],
|
||||
'with COUNT argument - without ANY option' => [
|
||||
['destination', 'source', new FromLonLat(1.1, 2.2), new ByRadius(1, 'km'), null, 20],
|
||||
['destination', 'source', 'FROMLONLAT', 1.1, 2.2, 'BYRADIUS', 1, 'km', 'COUNT', 20]
|
||||
],
|
||||
'with COUNT argument - with ANY option' => [
|
||||
['destination', 'source', new FromLonLat(1.1, 2.2), new ByRadius(1, 'km'), null, 20, true],
|
||||
['destination', 'source', 'FROMLONLAT', 1.1, 2.2, 'BYRADIUS', 1, 'km', 'COUNT', 20, 'ANY']
|
||||
],
|
||||
'with STOREDIST argument' => [
|
||||
['destination', 'source', new FromLonLat(1.1, 2.2), new ByRadius(1, 'km'), null, -1, false, true],
|
||||
['destination', 'source', 'FROMLONLAT', 1.1, 2.2, 'BYRADIUS', 1, 'km', 'STOREDIST']
|
||||
],
|
||||
'with all arguments' => [
|
||||
['destination', 'source', new FromLonLat(1.1, 2.2), new ByRadius(1, 'km'), 'asc', 20, true, true],
|
||||
['destination', 'source', 'FROMLONLAT', 1.1, 2.2, 'BYRADIUS', 1, 'km', 'ASC', 'COUNT', 20, 'ANY', 'STOREDIST']
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function coordinatesProvider(): array
|
||||
{
|
||||
return [
|
||||
'with default arguments - FROMLONLAT, BYRADIUS - all members' => [
|
||||
['key', 1.1, 2, 'member1'],
|
||||
['key', 2.1, 3, 'member2'],
|
||||
['key', 3.1, 4, 'member3'],
|
||||
'destination',
|
||||
'key',
|
||||
new FromLonLat(1, 4),
|
||||
new ByRadius(9999, 'km'),
|
||||
null,
|
||||
-1,
|
||||
false,
|
||||
3,
|
||||
['member1', 'member2', 'member3']
|
||||
],
|
||||
'with default arguments - FROMLONLAT, BYRADIUS - closest members' => [
|
||||
['key', 1.1, 2, 'member1'],
|
||||
['key', 2.1, 3, 'member2'],
|
||||
['key', 3.1, 4, 'member3'],
|
||||
'destination',
|
||||
'key',
|
||||
new FromLonLat(1, 3),
|
||||
new ByRadius(200, 'km'),
|
||||
null,
|
||||
-1,
|
||||
false,
|
||||
2,
|
||||
['member2', 'member1']
|
||||
],
|
||||
'with default arguments - FROMMEMBER, BYBOX - all members' => [
|
||||
['key', 1.1, 2, 'member1'],
|
||||
['key', 2.1, 3, 'member2'],
|
||||
['key', 3.1, 4, 'member3'],
|
||||
'destination',
|
||||
'key',
|
||||
new FromMember('member2'),
|
||||
new ByBox(999, 999, 'km'),
|
||||
null,
|
||||
-1,
|
||||
false,
|
||||
3,
|
||||
['member1', 'member2', 'member3']
|
||||
],
|
||||
'with default arguments - FROMMEMBER, BYBOX - closest members' => [
|
||||
['key', 1.1, 2, 'member1'],
|
||||
['key', 2.1, 3, 'member2'],
|
||||
['key', 3.1, 4, 'member3'],
|
||||
'destination',
|
||||
'key',
|
||||
new FromMember('member1'),
|
||||
new ByBox(300, 300, 'km'),
|
||||
null,
|
||||
-1,
|
||||
false,
|
||||
2,
|
||||
['member1', 'member2']
|
||||
],
|
||||
'with ASC modifier' => [
|
||||
['key', 1.1, 2, 'member1'],
|
||||
['key', 2.1, 3, 'member2'],
|
||||
['key', 3.1, 4, 'member3'],
|
||||
'destination',
|
||||
'key',
|
||||
new FromLonLat(1, 4),
|
||||
new ByRadius(9999, 'km'),
|
||||
'asc',
|
||||
-1,
|
||||
false,
|
||||
3,
|
||||
['member2', 'member1', 'member3']
|
||||
],
|
||||
'with DESC modifier' => [
|
||||
['key', 1.1, 2, 'member1'],
|
||||
['key', 2.1, 3, 'member2'],
|
||||
['key', 3.1, 4, 'member3'],
|
||||
'destination',
|
||||
'key',
|
||||
new FromLonLat(1, 4),
|
||||
new ByRadius(9999, 'km'),
|
||||
'desc',
|
||||
-1,
|
||||
false,
|
||||
3,
|
||||
['member3', 'member1', 'member2']
|
||||
],
|
||||
'with COUNT modifier - without ANY option' => [
|
||||
['key', 1.1, 2, 'member1'],
|
||||
['key', 2.1, 3, 'member2'],
|
||||
['key', 3.1, 4, 'member3'],
|
||||
'destination',
|
||||
'key',
|
||||
new FromLonLat(1, 4),
|
||||
new ByRadius(9999, 'km'),
|
||||
null,
|
||||
1,
|
||||
false,
|
||||
1,
|
||||
['member2']
|
||||
],
|
||||
'with COUNT modifier - with ANY option' => [
|
||||
['key', 1.1, 2, 'member1'],
|
||||
['key', 2.1, 3, 'member2'],
|
||||
['key', 3.1, 4, 'member3'],
|
||||
'destination',
|
||||
'key',
|
||||
new FromLonLat(1, 4),
|
||||
new ByRadius(9999, 'km'),
|
||||
null,
|
||||
2,
|
||||
true,
|
||||
2,
|
||||
['member1', 'member2']
|
||||
],
|
||||
'with all arguments' => [
|
||||
['key', 1.1, 2, 'member1'],
|
||||
['key', 2.1, 3, 'member2'],
|
||||
['key', 3.1, 4, 'member3'],
|
||||
'destination',
|
||||
'key',
|
||||
new FromLonLat(1, 4),
|
||||
new ByRadius(9999, 'km'),
|
||||
'asc',
|
||||
2,
|
||||
true,
|
||||
2,
|
||||
['member2', 'member1']
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function unexpectedValuesProvider(): array
|
||||
{
|
||||
return [
|
||||
'with wrong FROM argument' => [
|
||||
['destination', 'source', false, new ByRadius(9999, 'km'), null, -1, false, false],
|
||||
InvalidArgumentException::class,
|
||||
'Invalid FROM argument value given'
|
||||
],
|
||||
'with wrong BY argument' => [
|
||||
['destination', 'source', new FromLonLat(1, 4), false, null, -1, false, false],
|
||||
InvalidArgumentException::class,
|
||||
'Invalid BY argument value given'
|
||||
],
|
||||
'with wrong sorting argument' => [
|
||||
['destination', 'source', new FromLonLat(1, 4), new ByRadius(9999, 'km'), 'wrong', -1, false, false],
|
||||
UnexpectedValueException::class,
|
||||
'Sorting argument accepts only: asc, desc values'
|
||||
],
|
||||
'with wrong COUNT argument' => [
|
||||
['destination', 'source', new FromLonLat(1, 4), new ByRadius(9999, 'km'), null, 0, false, false],
|
||||
UnexpectedValueException::class,
|
||||
'Wrong count argument value or position offset'
|
||||
],
|
||||
'with wrong STOREDIST argument' => [
|
||||
['destination', 'source', new FromLonLat(1, 4), new ByRadius(9999, 'km'), null, 0, false, 'wrong'],
|
||||
UnexpectedValueException::class,
|
||||
'Wrong STOREDIST argument type'
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,472 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Predis\Command\Argument\Geospatial\ByBox;
|
||||
use Predis\Command\Argument\Geospatial\ByInterface;
|
||||
use Predis\Command\Argument\Geospatial\ByRadius;
|
||||
use Predis\Command\Argument\Geospatial\FromInterface;
|
||||
use Predis\Command\Argument\Geospatial\FromLonLat;
|
||||
use Predis\Command\Argument\Geospatial\FromMember;
|
||||
use UnexpectedValueException;
|
||||
|
||||
class GEOSEARCH_Test extends PredisCommandTestCase
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function getExpectedCommand(): string
|
||||
{
|
||||
return GEOSEARCH::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function getExpectedId(): string
|
||||
{
|
||||
return 'GEOSEARCH';
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
* @dataProvider argumentsProvider
|
||||
*/
|
||||
public function testFilterArguments(array $actualArguments, array $expectedArguments): void
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
$command->setArguments($actualArguments);
|
||||
|
||||
$this->assertSameValues($expectedArguments, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
* @dataProvider responsesProvider
|
||||
*/
|
||||
public function testParseResponse(array $actualResponse, array $expectedResponse): void
|
||||
{
|
||||
$this->assertSame($expectedResponse, $this->getCommand()->parseResponse($actualResponse));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @dataProvider coordinatesProvider
|
||||
* @param array $firstCoordinates
|
||||
* @param array $secondCoordinates
|
||||
* @param array $thirdCoordinates
|
||||
* @param string $key
|
||||
* @param FromInterface $from
|
||||
* @param ByInterface $by
|
||||
* @param string|null $sorting
|
||||
* @param int $count
|
||||
* @param bool $any
|
||||
* @param bool $withCoord
|
||||
* @param bool $withDist
|
||||
* @param bool $withHash
|
||||
* @param array $expectedResponse
|
||||
* @return void
|
||||
* @requiresRedisVersion >= 6.2.0
|
||||
*/
|
||||
public function testReturnsSearchedGeospatialCoordinates(
|
||||
array $firstCoordinates,
|
||||
array $secondCoordinates,
|
||||
array $thirdCoordinates,
|
||||
string $key,
|
||||
FromInterface $from,
|
||||
ByInterface $by,
|
||||
?string $sorting,
|
||||
int $count,
|
||||
bool $any,
|
||||
bool $withCoord,
|
||||
bool $withDist,
|
||||
bool $withHash,
|
||||
array $expectedResponse
|
||||
): void {
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->geoadd(...$firstCoordinates);
|
||||
$redis->geoadd(...$secondCoordinates);
|
||||
$redis->geoadd(...$thirdCoordinates);
|
||||
|
||||
$this->assertSame(
|
||||
$expectedResponse,
|
||||
$redis->geosearch($key, $from, $by, $sorting, $count, $any, $withCoord, $withDist, $withHash)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @dataProvider unexpectedValuesProvider
|
||||
* @param array $arguments
|
||||
* @param string $expectedException
|
||||
* @param string $expectedExceptionMessage
|
||||
* @return void
|
||||
* @requiresRedisVersion >= 6.2.0
|
||||
*/
|
||||
public function testThrowsExceptionOnUnexpectedValueProvided(
|
||||
array $arguments,
|
||||
string $expectedException,
|
||||
string $expectedExceptionMessage
|
||||
): void {
|
||||
$redis = $this->getClient();
|
||||
|
||||
$this->expectException($expectedException);
|
||||
$this->expectExceptionMessage($expectedExceptionMessage);
|
||||
|
||||
$redis->geosearch(...$arguments);
|
||||
}
|
||||
|
||||
public function argumentsProvider(): array
|
||||
{
|
||||
return [
|
||||
'with default arguments - FROMLONLAT, BYRADIUS' => [
|
||||
['key', new FromLonLat(1.1, 2.2), new ByRadius(1, 'km')],
|
||||
['key', 'FROMLONLAT', 1.1, 2.2, 'BYRADIUS', 1, 'km']
|
||||
],
|
||||
'with default arguments - FROMMEMBER, BYBOX' => [
|
||||
['key', new FromMember('member'), new ByBox(1,1, 'km')],
|
||||
['key', 'FROMMEMBER', 'member', 'BYBOX', 1, 1, 'km']
|
||||
],
|
||||
'with ASC sorting' => [
|
||||
['key', new FromLonLat(1.1, 2.2), new ByRadius(1, 'km'), 'asc'],
|
||||
['key', 'FROMLONLAT', 1.1, 2.2, 'BYRADIUS', 1, 'km', 'ASC']
|
||||
],
|
||||
'with DESC sorting' => [
|
||||
['key', new FromLonLat(1.1, 2.2), new ByRadius(1, 'km'), 'desc'],
|
||||
['key', 'FROMLONLAT', 1.1, 2.2, 'BYRADIUS', 1, 'km', 'DESC']
|
||||
],
|
||||
'with COUNT argument - without ANY option' => [
|
||||
['key', new FromLonLat(1.1, 2.2), new ByRadius(1, 'km'), null, 20],
|
||||
['key', 'FROMLONLAT', 1.1, 2.2, 'BYRADIUS', 1, 'km', 'COUNT', 20]
|
||||
],
|
||||
'with COUNT argument - with ANY option' => [
|
||||
['key', new FromLonLat(1.1, 2.2), new ByRadius(1, 'km'), null, 20, true],
|
||||
['key', 'FROMLONLAT', 1.1, 2.2, 'BYRADIUS', 1, 'km', 'COUNT', 20, 'ANY']
|
||||
],
|
||||
'with WITHCOORD argument' => [
|
||||
['key', new FromLonLat(1.1, 2.2), new ByRadius(1, 'km'), null, -1, false, true],
|
||||
['key', 'FROMLONLAT', 1.1, 2.2, 'BYRADIUS', 1, 'km', 'WITHCOORD']
|
||||
],
|
||||
'with WITHDIST argument' => [
|
||||
['key', new FromLonLat(1.1, 2.2), new ByRadius(1, 'km'), null, -1, false, false, true],
|
||||
['key', 'FROMLONLAT', 1.1, 2.2, 'BYRADIUS', 1, 'km', 'WITHDIST']
|
||||
],
|
||||
'with WITHHASH argument' => [
|
||||
['key', new FromLonLat(1.1, 2.2), new ByRadius(1, 'km'), null, -1, false, false, false, true],
|
||||
['key', 'FROMLONLAT', 1.1, 2.2, 'BYRADIUS', 1, 'km', 'WITHHASH']
|
||||
],
|
||||
'with all arguments' => [
|
||||
['key', new FromLonLat(1.1, 2.2), new ByRadius(1, 'km'), 'asc', 20, true, true, true, true],
|
||||
['key', 'FROMLONLAT', 1.1, 2.2, 'BYRADIUS', 1, 'km', 'ASC', 'COUNT', 20, 'ANY', 'WITHCOORD', 'WITHDIST', 'WITHHASH']
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function responsesProvider(): array
|
||||
{
|
||||
return [
|
||||
'without WITH modifiers' => [
|
||||
['member1', 'member2', 'member3'],
|
||||
['member1', 'member2', 'member3'],
|
||||
],
|
||||
'with WITHCOORD modifier' => [
|
||||
[['member1', [1.1, 2.2]], ['member2', [2.2, 3.3]], ['member3', [3.3, 4.4]]],
|
||||
[
|
||||
'member1' => ['lng' => 1.1, 'lat' => 2.2],
|
||||
'member2' => ['lng' => 2.2, 'lat' => 3.3],
|
||||
'member3' => ['lng' => 3.3, 'lat' => 4.4]]
|
||||
],
|
||||
'with WITHDIST modifier' => [
|
||||
[['member1', '111.111'], ['member2', '222.222'], ['member3', '333.333']],
|
||||
[
|
||||
'member1' => ['dist' => 111.111],
|
||||
'member2' => ['dist' => 222.222],
|
||||
'member3' => ['dist' => 333.333],
|
||||
],
|
||||
],
|
||||
'with WITHHASH modifier' => [
|
||||
[['member1', 1111], ['member2', 2222], ['member3', 3333]],
|
||||
[
|
||||
'member1' => ['hash' => 1111],
|
||||
'member2' => ['hash' => 2222],
|
||||
'member3' => ['hash' => 3333],
|
||||
],
|
||||
],
|
||||
'with all WITH modifiers' => [
|
||||
[
|
||||
['member1', '111.111', 1111, [1.1, 2.2]],
|
||||
['member2', '222.222', 2222, [2.2, 3.3]],
|
||||
['member3', '333.333', 3333, [3.3, 4.4]],
|
||||
],
|
||||
[
|
||||
'member1' => [
|
||||
'dist' => 111.111,
|
||||
'hash' => 1111,
|
||||
'lng' => 1.1,
|
||||
'lat' => 2.2,
|
||||
],
|
||||
'member2' => [
|
||||
'dist' => 222.222,
|
||||
'hash' => 2222,
|
||||
'lng' => 2.2,
|
||||
'lat' => 3.3,
|
||||
],
|
||||
'member3' => [
|
||||
'dist' => 333.333,
|
||||
'hash' => 3333,
|
||||
'lng' => 3.3,
|
||||
'lat' => 4.4,
|
||||
],
|
||||
],
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function coordinatesProvider(): array
|
||||
{
|
||||
return [
|
||||
'with default arguments - FROMLONLAT, BYRADIUS - all members' => [
|
||||
['key', 1.1, 2, 'member1'],
|
||||
['key', 2.1, 3, 'member2'],
|
||||
['key', 3.1, 4, 'member3'],
|
||||
'key',
|
||||
new FromLonLat(1, 4),
|
||||
new ByRadius(9999, 'km'),
|
||||
null,
|
||||
-1,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
['member1', 'member2', 'member3']
|
||||
],
|
||||
'with default arguments - FROMLONLAT, BYRADIUS - closest members' => [
|
||||
['key', 1.1, 2, 'member1'],
|
||||
['key', 2.1, 3, 'member2'],
|
||||
['key', 3.1, 4, 'member3'],
|
||||
'key',
|
||||
new FromLonLat(1, 3),
|
||||
new ByRadius(200, 'km'),
|
||||
null,
|
||||
-1,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
['member2', 'member1']
|
||||
],
|
||||
'with default arguments - FROMMEMBER, BYBOX - all members' => [
|
||||
['key', 1.1, 2, 'member1'],
|
||||
['key', 2.1, 3, 'member2'],
|
||||
['key', 3.1, 4, 'member3'],
|
||||
'key',
|
||||
new FromMember('member2'),
|
||||
new ByBox(999, 999, 'km'),
|
||||
null,
|
||||
-1,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
['member1', 'member2', 'member3']
|
||||
],
|
||||
'with default arguments - FROMMEMBER, BYBOX - closest members' => [
|
||||
['key', 1.1, 2, 'member1'],
|
||||
['key', 2.1, 3, 'member2'],
|
||||
['key', 3.1, 4, 'member3'],
|
||||
'key',
|
||||
new FromMember('member1'),
|
||||
new ByBox(300, 300, 'km'),
|
||||
null,
|
||||
-1,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
['member1', 'member2']
|
||||
],
|
||||
'with ASC modifier' => [
|
||||
['key', 1.1, 2, 'member1'],
|
||||
['key', 2.1, 3, 'member2'],
|
||||
['key', 3.1, 4, 'member3'],
|
||||
'key',
|
||||
new FromLonLat(1, 4),
|
||||
new ByRadius(9999, 'km'),
|
||||
'asc',
|
||||
-1,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
['member2', 'member1', 'member3']
|
||||
],
|
||||
'with DESC modifier' => [
|
||||
['key', 1.1, 2, 'member1'],
|
||||
['key', 2.1, 3, 'member2'],
|
||||
['key', 3.1, 4, 'member3'],
|
||||
'key',
|
||||
new FromLonLat(1, 4),
|
||||
new ByRadius(9999, 'km'),
|
||||
'desc',
|
||||
-1,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
['member3', 'member1', 'member2']
|
||||
],
|
||||
'with COUNT modifier - without ANY option' => [
|
||||
['key', 1.1, 2, 'member1'],
|
||||
['key', 2.1, 3, 'member2'],
|
||||
['key', 3.1, 4, 'member3'],
|
||||
'key',
|
||||
new FromLonLat(1, 4),
|
||||
new ByRadius(9999, 'km'),
|
||||
null,
|
||||
1,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
['member2']
|
||||
],
|
||||
'with COUNT modifier - with ANY option' => [
|
||||
['key', 1.1, 2, 'member1'],
|
||||
['key', 2.1, 3, 'member2'],
|
||||
['key', 3.1, 4, 'member3'],
|
||||
'key',
|
||||
new FromLonLat(1, 4),
|
||||
new ByRadius(9999, 'km'),
|
||||
null,
|
||||
2,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
['member1', 'member2']
|
||||
],
|
||||
'with WITHCOORD modifier' => [
|
||||
['key', 1.1, 2, 'member1'],
|
||||
['key', 2.1, 3, 'member2'],
|
||||
['key', 3.1, 4, 'member3'],
|
||||
'key',
|
||||
new FromLonLat(1, 4),
|
||||
new ByRadius(9999, 'km'),
|
||||
null,
|
||||
-1,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
[
|
||||
'member1' => ['lng' => 1.1, 'lat' => 2.0],
|
||||
'member2' => ['lng' => 2.1, 'lat' => 3.0],
|
||||
'member3' => ['lng' => 3.1, 'lat' => 4.0],
|
||||
]
|
||||
],
|
||||
'with WITHDIST modifier' => [
|
||||
['key', 1.1, 2, 'member1'],
|
||||
['key', 2.1, 3, 'member2'],
|
||||
['key', 3.1, 4, 'member3'],
|
||||
'key',
|
||||
new FromLonLat(1, 4),
|
||||
new ByRadius(9999, 'km'),
|
||||
null,
|
||||
-1,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
[
|
||||
'member1' => ['dist' => 222.7297],
|
||||
'member2' => ['dist' => 165.1798],
|
||||
'member3' => ['dist' => 233.006],
|
||||
]
|
||||
],
|
||||
'with WITHHASH modifier' => [
|
||||
['key', 1.1, 2, 'member1'],
|
||||
['key', 2.1, 3, 'member2'],
|
||||
['key', 3.1, 4, 'member3'],
|
||||
'key',
|
||||
new FromLonLat(1, 4),
|
||||
new ByRadius(9999, 'km'),
|
||||
null,
|
||||
-1,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
[
|
||||
'member1' => ['hash' => 3378086406303657],
|
||||
'member2' => ['hash' => 3378965307136228],
|
||||
'member3' => ['hash' => 3379626601756294],
|
||||
]
|
||||
],
|
||||
'with all arguments' => [
|
||||
['key', 1.1, 2, 'member1'],
|
||||
['key', 2.1, 3, 'member2'],
|
||||
['key', 3.1, 4, 'member3'],
|
||||
'key',
|
||||
new FromLonLat(1, 4),
|
||||
new ByRadius(9999, 'km'),
|
||||
'asc',
|
||||
1,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
[
|
||||
'member1' => [
|
||||
'dist' => 222.7297,
|
||||
'hash' => 3378086406303657,
|
||||
'lng' => 1.1,
|
||||
'lat' => 2.0,
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function unexpectedValuesProvider(): array
|
||||
{
|
||||
return [
|
||||
'with wrong FROM argument' => [
|
||||
['key', false, new ByRadius(9999, 'km'), null, -1, false, false],
|
||||
InvalidArgumentException::class,
|
||||
'Invalid FROM argument value given'
|
||||
],
|
||||
'with wrong BY argument' => [
|
||||
['key', new FromLonLat(1, 4), false, null, -1, false, false],
|
||||
InvalidArgumentException::class,
|
||||
'Invalid BY argument value given'
|
||||
],
|
||||
'with wrong sorting argument' => [
|
||||
['key', new FromLonLat(1, 4), new ByRadius(9999, 'km'), 'wrong', -1, false, false],
|
||||
UnexpectedValueException::class,
|
||||
'Sorting argument accepts only: asc, desc values'
|
||||
],
|
||||
'with wrong COUNT argument' => [
|
||||
['key', new FromLonLat(1, 4), new ByRadius(9999, 'km'), null, 0, false, false],
|
||||
UnexpectedValueException::class,
|
||||
'Wrong count argument value or position offset'
|
||||
],
|
||||
'with wrong WITHCOORD argument' => [
|
||||
['key', new FromLonLat(1, 4), new ByRadius(9999, 'km'), null, 0, false, 'wrong'],
|
||||
UnexpectedValueException::class,
|
||||
'Wrong WITHCOORD argument type'
|
||||
],
|
||||
'with wrong WITHDIST argument' => [
|
||||
['key', new FromLonLat(1, 4), new ByRadius(9999, 'km'), null, 0, false, false, 'wrong'],
|
||||
UnexpectedValueException::class,
|
||||
'Wrong WITHDIST argument type'
|
||||
],
|
||||
'with wrong WITHHASH argument' => [
|
||||
['key', new FromLonLat(1, 4), new ByRadius(9999, 'km'), null, 0, false, false, false, 'wrong'],
|
||||
UnexpectedValueException::class,
|
||||
'Wrong WITHHASH argument type'
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
class GETDEL_Test extends PredisCommandTestCase
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function getExpectedCommand(): string
|
||||
{
|
||||
return GETDEL::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function getExpectedId(): string
|
||||
{
|
||||
return 'GETDEL';
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testFilterArguments(): void
|
||||
{
|
||||
$arguments = ['key'];
|
||||
$expected = ['key'];
|
||||
|
||||
$command = $this->getCommand();
|
||||
$command->setArguments($arguments);
|
||||
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testParseResponse(): void
|
||||
{
|
||||
$this->assertSame(1, $this->getCommand()->parseResponse(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @return void
|
||||
* @requiresRedisVersion >= 6.2.0
|
||||
*/
|
||||
public function testReturnsValueForGivenKeyAndDeleteIt(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
$expectedKey = 'key';
|
||||
$expectedValue = 'value';
|
||||
|
||||
$redis->set($expectedKey, $expectedValue);
|
||||
|
||||
$actualResponse = $redis->getdel($expectedKey);
|
||||
|
||||
$this->assertSame($expectedValue, $actualResponse);
|
||||
$this->assertNull($redis->get($expectedKey));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use UnexpectedValueException;
|
||||
|
||||
/**
|
||||
* @group commands
|
||||
* @group realm-string
|
||||
*/
|
||||
class GETEX_Test extends PredisCommandTestCase
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCommand(): string
|
||||
{
|
||||
return GETEX::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedId(): string
|
||||
{
|
||||
return 'GETEX';
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
* @dataProvider argumentsProvider
|
||||
*/
|
||||
public function testFilterArguments(array $actualArguments, array $expectedArguments): void
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
$command->setArguments($actualArguments);
|
||||
|
||||
$this->assertSame($expectedArguments, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testParseResponse(): void
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
|
||||
$this->assertSame(1, $command->parseResponse(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @dataProvider keysProvider
|
||||
* @param array $kvPair
|
||||
* @param array $arguments
|
||||
* @param string $expectedResponse
|
||||
* @return void
|
||||
* @requiresRedisVersion >= 6.2.0
|
||||
*/
|
||||
public function testReturnsValueAndSetExpirationTimeForGivenKey(
|
||||
array $kvPair,
|
||||
array $arguments,
|
||||
string $expectedResponse
|
||||
): void {
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->set(...$kvPair);
|
||||
|
||||
$this->assertSame($expectedResponse, $redis->getex(...$arguments));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @dataProvider unexpectedValuesProvider
|
||||
* @param array $arguments
|
||||
* @param string $expectedExceptionMessage
|
||||
* @return void
|
||||
* @requiresRedisVersion >= 6.2.0
|
||||
*/
|
||||
public function testThrowsExceptionOnUnexpectedValueGiven(
|
||||
array $arguments,
|
||||
string $expectedExceptionMessage
|
||||
): void {
|
||||
$redis = $this->getClient();
|
||||
|
||||
$this->expectException(UnexpectedValueException::class);
|
||||
$this->expectExceptionMessage($expectedExceptionMessage);
|
||||
|
||||
$redis->getex(...$arguments);
|
||||
}
|
||||
|
||||
public function argumentsProvider(): array
|
||||
{
|
||||
return [
|
||||
'with default arguments' => [
|
||||
['key'],
|
||||
['key']
|
||||
],
|
||||
'with EX modifier' => [
|
||||
['key', 'ex', 1],
|
||||
['key', 'EX', 1],
|
||||
],
|
||||
'with PX modifier' => [
|
||||
['key', 'px', 1],
|
||||
['key', 'PX', 1],
|
||||
],
|
||||
'with EXAT modifier' => [
|
||||
['key', 'exat', 1],
|
||||
['key', 'EXAT', 1],
|
||||
],
|
||||
'with PXAT modifier' => [
|
||||
['key', 'pxat', 1],
|
||||
['key', 'PXAT', 1],
|
||||
],
|
||||
'with PERSIST modifier' => [
|
||||
['key', 'persist'],
|
||||
['key', 'PERSIST']
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function keysProvider(): array
|
||||
{
|
||||
return [
|
||||
'without expiration time' => [
|
||||
['key', 'value'],
|
||||
['key', '', false],
|
||||
'value',
|
||||
],
|
||||
'with expiration - EX modifier' => [
|
||||
['key', 'value'],
|
||||
['key', 'ex', 10],
|
||||
'value'
|
||||
],
|
||||
'with expiration - PX modifier' => [
|
||||
['key', 'value'],
|
||||
['key', 'px', 10],
|
||||
'value'
|
||||
],
|
||||
'with expiration - EXAT modifier' => [
|
||||
['key', 'value'],
|
||||
['key', 'exat', 10],
|
||||
'value'
|
||||
],
|
||||
'with expiration - PXAT modifier' => [
|
||||
['key', 'value'],
|
||||
['key', 'pxat', 10],
|
||||
'value'
|
||||
],
|
||||
'with expiration - PERSIST modifier' => [
|
||||
['key', 'value'],
|
||||
['key', 'persist'],
|
||||
'value'
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function unexpectedValuesProvider(): array
|
||||
{
|
||||
return [
|
||||
'with wrong modifier' => [
|
||||
['key', 'wrong', 1],
|
||||
'Modifier argument accepts only: ex, px, exat, pxat, persist values'
|
||||
],
|
||||
'without value provided' => [
|
||||
['key', 'ex'],
|
||||
'You should provide value for current modifier'
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Response\ServerException;
|
||||
|
||||
class HRANDFIELD_Test extends PredisCommandTestCase
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function getExpectedCommand(): string
|
||||
{
|
||||
return HRANDFIELD::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function getExpectedId(): string
|
||||
{
|
||||
return 'HRANDFIELD';
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
* @dataProvider argumentsProvider
|
||||
* @param array $actualArguments
|
||||
* @param array $expectedArguments
|
||||
* @return void
|
||||
*/
|
||||
public function testFilterArguments(array $actualArguments, array $expectedArguments): void
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
$command->setArguments($actualArguments);
|
||||
|
||||
$this->assertSame($expectedArguments, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testParseResponse(): void
|
||||
{
|
||||
$this->assertSame(1, $this->getCommand()->parseResponse(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @dataProvider hashesProvider
|
||||
* @param array $hash
|
||||
* @param string $key
|
||||
* @param int $count
|
||||
* @param bool $withValues
|
||||
* @param array $expectedResponse
|
||||
* @return void
|
||||
* @requiresRedisVersion >= 6.2.0
|
||||
*/
|
||||
public function testReturnsRandomFieldsFromHash(
|
||||
array $hash,
|
||||
string $key,
|
||||
int $count,
|
||||
bool $withValues,
|
||||
array $expectedResponse
|
||||
): void {
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->hset($key, ...$hash);
|
||||
$actualResponse = $redis->hrandfield($key, $count, $withValues);
|
||||
|
||||
$this->assertOneOf($expectedResponse, $actualResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @requiresRedisVersion >= 6.2.0
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType(): void
|
||||
{
|
||||
$this->expectException(ServerException::class);
|
||||
$this->expectExceptionMessage('Operation against a key holding the wrong kind of value');
|
||||
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->set('foo', 'bar');
|
||||
$redis->hrandfield('foo');
|
||||
}
|
||||
|
||||
public function argumentsProvider(): array
|
||||
{
|
||||
return [
|
||||
'with default arguments' => [
|
||||
['key'],
|
||||
['key']
|
||||
],
|
||||
'with count argument' => [
|
||||
['key', 1],
|
||||
['key', 1]
|
||||
],
|
||||
'with WITHVALUES argument' => [
|
||||
['key', 1, true],
|
||||
['key', 1, 'WITHVALUES']
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function hashesProvider(): array
|
||||
{
|
||||
return [
|
||||
'one field - without values' => [
|
||||
['key1', 'value1', 'key2', 'value2', 'key3', 'value3'],
|
||||
'key',
|
||||
1,
|
||||
false,
|
||||
['key1', 'key2', 'key3']
|
||||
],
|
||||
'one field - with values' => [
|
||||
['key1', 'value1', 'key2', 'value2', 'key3', 'value3'],
|
||||
'key',
|
||||
1,
|
||||
true,
|
||||
['key1', 'value1', 'key2', 'value2', 'key3', 'value3']
|
||||
],
|
||||
'multiple fields - without values' => [
|
||||
['key1', 'value1', 'key2', 'value2', 'key3', 'value3'],
|
||||
'key',
|
||||
2,
|
||||
false,
|
||||
['key1', 'key2', 'key3'],
|
||||
],
|
||||
'multiple fields - with values' => [
|
||||
['key1', 'value1', 'key2', 'value2', 'key3', 'value3'],
|
||||
'key',
|
||||
2,
|
||||
true,
|
||||
['key1', 'value1', 'key2', 'value2', 'key3', 'value3'],
|
||||
],
|
||||
'multiple fields - allows same fields' => [
|
||||
['key1', 'value1', 'key2', 'value2', 'key3', 'value3'],
|
||||
'key',
|
||||
-2,
|
||||
false,
|
||||
['key1', 'key2', 'key3'],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
<?php
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Response\ServerException;
|
||||
|
||||
/**
|
||||
* @group commands
|
||||
* @group realm-list
|
||||
*/
|
||||
class LMOVE_Test extends PredisCommandTestCase
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function getExpectedCommand(): string
|
||||
{
|
||||
return LMOVE::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function getExpectedId(): string
|
||||
{
|
||||
return 'LMOVE';
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testFilterArguments(): void
|
||||
{
|
||||
$arguments = ['list', 'argument1', 'argument2', 'argument3'];
|
||||
$expected = ['list', 'argument1', 'argument2', 'argument3'];
|
||||
|
||||
$command = $this->getCommand();
|
||||
$command->setArguments($arguments);
|
||||
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testParseResponse(): void
|
||||
{
|
||||
$this->assertSame(1, $this->getCommand()->parseResponse(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @dataProvider listsProvider
|
||||
* @param array $firstList
|
||||
* @param array $secondList
|
||||
* @param string $where
|
||||
* @param string $to
|
||||
* @param string $expectedResponse
|
||||
* @param array $expectedModifiedFirstList
|
||||
* @param array $expectedModifiedSecondList
|
||||
* @return void
|
||||
* @requiresRedisVersion >= 6.2.0
|
||||
*/
|
||||
public function testReturnsCorrectListElement(
|
||||
array $firstList,
|
||||
array $secondList,
|
||||
string $where,
|
||||
string $to,
|
||||
string $expectedResponse,
|
||||
array $expectedModifiedFirstList,
|
||||
array $expectedModifiedSecondList
|
||||
): void {
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->rpush('test-lmove1', $firstList);
|
||||
$redis->rpush('test-lmove2', $secondList);
|
||||
|
||||
$actualResponse = $redis->lmove('test-lmove1', 'test-lmove2', $where, $to);
|
||||
|
||||
$this->assertSame($expectedResponse, $actualResponse);
|
||||
$this->assertSame($expectedModifiedFirstList, $redis->lrange('test-lmove1', 0, -1));
|
||||
$this->assertSame($expectedModifiedSecondList, $redis->lrange('test-lmove2', 0, -1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @return void
|
||||
* @requiresRedisVersion >= 6.2.0
|
||||
*/
|
||||
public function testReturnsNullAndNoOperationPerformedOnNonExistingSource(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
$expectedList = ['element1', 'element2', 'element3'];
|
||||
|
||||
$redis->rpush('test-lmove1', $expectedList);
|
||||
|
||||
$actualResponse = $redis->lmove('test-lmove2', 'test-lmove1', 'LEFT', 'LEFT');
|
||||
|
||||
$this->assertNull($actualResponse);
|
||||
$this->assertSame($expectedList, $redis->lrange('test-lmove1', 0, -1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @dataProvider sameListProvider
|
||||
* @param array $list
|
||||
* @param string $where
|
||||
* @param string $to
|
||||
* @param string $expectedResponse
|
||||
* @param array $expectedModifiedList
|
||||
* @return void
|
||||
* @requiresRedisVersion >= 6.2.0
|
||||
*/
|
||||
public function testReturnsCorrectListElementAndListRotationPerformedOnTheSameListOperation(
|
||||
array $list,
|
||||
string $where,
|
||||
string $to,
|
||||
string $expectedResponse,
|
||||
array $expectedModifiedList
|
||||
): void {
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->rpush('test-lmove1', $list);
|
||||
|
||||
$actualResponse = $redis->lmove('test-lmove1', 'test-lmove1', $where, $to);
|
||||
|
||||
$this->assertSame($expectedResponse, $actualResponse);
|
||||
$this->assertSame($expectedModifiedList, $redis->lrange('test-lmove1', 0, -1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @return void
|
||||
* @requiresRedisVersion >= 6.2.0
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType(): void
|
||||
{
|
||||
$this->expectException(ServerException::class);
|
||||
$this->expectExceptionMessage('Operation against a key holding the wrong kind of value');
|
||||
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->set('foo', 'bar');
|
||||
$redis->lmove('foo', 'test-lmove', 'LEFT', 'LEFT');
|
||||
}
|
||||
|
||||
public function listsProvider(): array
|
||||
{
|
||||
return [
|
||||
'move first element from list into head of another list' => [
|
||||
['element1', 'element2', 'element3'],
|
||||
['element4', 'element5', 'element6'],
|
||||
'LEFT',
|
||||
'LEFT',
|
||||
'element1',
|
||||
['element2', 'element3'],
|
||||
['element1', 'element4', 'element5', 'element6'],
|
||||
],
|
||||
'move first element from list into tail of another list' => [
|
||||
['element1', 'element2', 'element3'],
|
||||
['element4', 'element5', 'element6'],
|
||||
'LEFT',
|
||||
'RIGHT',
|
||||
'element1',
|
||||
['element2', 'element3'],
|
||||
['element4', 'element5', 'element6', 'element1'],
|
||||
],
|
||||
'move last element from list into head of another list' => [
|
||||
['element1', 'element2', 'element3'],
|
||||
['element4', 'element5', 'element6'],
|
||||
'RIGHT',
|
||||
'LEFT',
|
||||
'element3',
|
||||
['element1', 'element2'],
|
||||
['element3', 'element4', 'element5', 'element6'],
|
||||
],
|
||||
'move last element from list into tail of another list' => [
|
||||
['element1', 'element2', 'element3'],
|
||||
['element4', 'element5', 'element6'],
|
||||
'RIGHT',
|
||||
'RIGHT',
|
||||
'element3',
|
||||
['element1', 'element2'],
|
||||
['element4', 'element5', 'element6', 'element3'],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function sameListProvider(): array
|
||||
{
|
||||
return [
|
||||
'list rotation - head into tail' => [
|
||||
['element1', 'element2', 'element3'],
|
||||
'LEFT',
|
||||
'RIGHT',
|
||||
'element1',
|
||||
['element2', 'element3', 'element1'],
|
||||
],
|
||||
'list rotation - tail into head' => [
|
||||
['element1', 'element2', 'element3'],
|
||||
'RIGHT',
|
||||
'LEFT',
|
||||
'element3',
|
||||
['element3', 'element1', 'element2'],
|
||||
],
|
||||
'list rotation - head into head' => [
|
||||
['element1', 'element2', 'element3'],
|
||||
'LEFT',
|
||||
'LEFT',
|
||||
'element1',
|
||||
['element1', 'element2', 'element3'],
|
||||
],
|
||||
'list rotation - tail into tail' => [
|
||||
['element1', 'element2', 'element3'],
|
||||
'RIGHT',
|
||||
'RIGHT',
|
||||
'element3',
|
||||
['element1', 'element2', 'element3'],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user