Compare commits

..

15 Commits

Author SHA1 Message Date
Till Krüss be75254ab6 bump dev version [skip ci] 2025-11-12 10:01:35 -08:00
Till Krüss 07105e0506 tag v2.4.1 2025-11-12 10:00:11 -08:00
Vladyslav Vildanov 07dc6ba6d2 fix(conn): Removed automatic conn_uid assignment (#1551)
* fix(conn): Removed automatic conn_uid assignment

* Restrict redis version

* Updated CHANGELOG.md

* Added test case

* Update CHANGELOG.md

---------

Co-authored-by: Till Krüss <tillkruss@users.noreply.github.com>
2025-06-05 09:54:27 +03:00
Till Krüss 5142011581 Update CHANGELOG.md 2025-05-27 09:55:55 -07:00
Tim Düsterhus c4b9c34d86 Fix return type for ZCOUNT (#1546)
* Fix return type for ZCOUNT

ZCOUNT returns an `int`:

> Integer reply: the number of members in the specified score range.

* Update CHANGELOG.md

---------

Co-authored-by: Till Krüss <tillkruss@users.noreply.github.com>
2025-05-27 10:39:05 +03:00
Till Krüss f49e13ee3a tag stable 2.4.0 2025-04-30 08:16:02 -07:00
Vladyslav Vildanov 6e3e2c0e78 [2.x] 8.0-RC2 testing (#1532) 2025-04-29 08:25:13 -07:00
Vladyslav Vildanov c35c422eda [2.x] Fix the problem of protocol loss during cluster MOVED/ASK (#1530)
Co-authored-by: Lynn Club <lynncho@live.com>
Co-authored-by: Lynn Club <10293848+lynnclub@users.noreply.github.com>
Co-authored-by: Till Krüss <tillkruss@users.noreply.github.com>
2025-04-17 08:49:19 -07:00
Till Krüss 1b5ed7d516 ZPOPMIN & ZPOPMAX prefix tests 2025-04-15 13:25:42 -07:00
vladvildanov 5df852f227 Added tests cases 2025-04-15 09:16:08 -07:00
Till Krüss 9418df1924 fix changelog branch check 2025-04-15 09:15:52 -07:00
Till Krüss 0e4b3829a7 fix changelog check 2025-04-15 09:07:26 -07:00
Till Krüss 65f6127fab add changelog check 2025-04-15 08:54:08 -07:00
Till Krüss 7ff24b19ae Merge pull request #1528 from predis/vv-2.x-readme-8.0-support
(2.x) Update README.md (Redis 8.0 support)
2025-04-14 09:11:07 -07:00
vladvildanov 2babfc91d7 Update README.md (Redis 8.0 support) 2025-04-14 18:42:11 +03:00
779 changed files with 6171 additions and 27629 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
[codespell]
skip=./.git,./src/Command/Redis/Search/FTSUGGET.php,./examples/Commands/Search/ft_sug_add_get_del_len.php
skip=./.git
check-hidden=
check-filenames=
builtin=clear,rare,informal,usage,code,names
+14 -2
View File
@@ -1,2 +1,14 @@
* @predis/maintainers
src/Relay* @tillkruss
# Default
* @tillkruss
# Redis commands
src/Command/Redis/* @predis/team @tillkruss
# Redis Stack
src/Command/Redis/Json/* @predis/team
src/Command/Redis/Search/* @predis/team
src/Command/Redis/TopK/* @predis/team
src/Command/Redis/TDigest/* @predis/team
src/Command/Redis/BloomFilter/* @predis/team
src/Command/Redis/CuckooFilter/* @predis/team
src/Command/Redis/CountMinSketch/* @predis/team
+9 -32
View File
@@ -3,8 +3,8 @@
services:
redis-official:
image: ${REDIS_IMAGE_NAME:-redis:8.0}
container_name: redis-official
image: ${REDIS_IMAGE_NAME:-redis:7.4}
container_name: redis-standalone
healthcheck:
test: [ "CMD", "redis-cli", "PING" ]
interval: 10s
@@ -12,23 +12,20 @@ services:
retries: 3
ports:
- "6379:6379"
command:
- --requirepass "foobar"
profiles:
- all
- official
- standalone
redis-clients:
image: ${REDIS_IMAGE_NAME:-redislabs/client-libs-test:8.0.2}
image: ${REDIS_IMAGE_NAME:-redislabs/client-libs-test:7.4.2}
container_name: redis-standalone
environment:
- TLS_ENABLED=yes
- REDIS_CLUSTER=no
- REDIS_PASSWORD=foobar
- PORT=6379
- TLS_PORT=6666
command: ${REDIS_EXTRA_ARGS:---enable-debug-command yes --enable-module-command yes --tls-auth-clients optional --save "" --requirepass "foobar"}
command: ${REDIS_EXTRA_ARGS:---enable-debug-command yes --enable-module-command yes --tls-auth-clients optional --save ""}
ports:
- 6379:6379
- 6666:6666 # TLS port
@@ -39,38 +36,19 @@ services:
- clients
- standalone
redis-unprotected:
image: ${REDIS_IMAGE_NAME:-redislabs/client-libs-test:8.0.2}
container_name: redis-unprotected
environment:
- TLS_ENABLED=no
- REDIS_CLUSTER=no
- PORT=6379
- TLS_PORT=6666
command: ${REDIS_EXTRA_ARGS:---enable-debug-command yes --enable-module-command yes --tls-auth-clients optional --save ""}
ports:
- 6380:6379
volumes:
- "./dockers/unprotected:/redis/work"
profiles:
- all
- clients
- unprotected
redis-cluster:
image: ${REDIS_IMAGE_NAME:-redislabs/client-libs-test:8.0.2}
image: ${REDIS_IMAGE_NAME:-redislabs/client-libs-test:7.4.2}
container_name: redis-cluster
environment:
- REDIS_CLUSTER=yes
- REDIS_PASSWORD=foobar
- NODES=6
- REPLICAS=1
- TLS_ENABLED=yes
- PORT=6372
- PORT=16379
- TLS_PORT=27379
command: ${REDIS_EXTRA_ARGS:---enable-debug-command yes --enable-module-command yes --tls-auth-clients optional --save "" --requirepass "foobar"}
command: ${REDIS_EXTRA_ARGS:---enable-debug-command yes --enable-module-command yes --tls-auth-clients optional --save ""}
ports:
- "6372-6377:6372-6377"
- "6372-6377:16379-16384"
volumes:
- "./dockers/cluster:/redis/work"
profiles:
@@ -85,9 +63,8 @@ services:
- "6479:6379"
environment:
- REDIS_CLUSTER=no
- REDIS_PASSWORD=foobar
- PORT=6379
command: ${REDIS_EXTRA_ARGS:---enable-debug-command yes --enable-module-command yes --save "" --requirepass "foobar"}
command: ${REDIS_EXTRA_ARGS:---enable-debug-command yes --enable-module-command yes --save ""}
volumes:
- "./dockers/redis-stack:/redis/work"
profiles:
-2
View File
@@ -1,8 +1,6 @@
name-template: 'v$NEXT_MINOR_VERSION'
tag-template: 'v$NEXT_MINOR_VERSION'
change-template: '- $TITLE (#$NUMBER)'
filter-by-comitish: true
commitish: v3.x
autolabeler:
- label: 'maintenance'
-29
View File
@@ -1,29 +0,0 @@
matrix:
- name: Markdown
expect_match: false
apsell:
lang: en
d: en_US
ignore-case: true
dictionary:
wordlists:
- .github/wordlist.txt
output: wordlist.dic
pipeline:
- pyspelling.filters.markdown:
markdown_extensions:
- markdown.extensions.extra:
- pyspelling.filters.html:
comments: false
attributes:
- alt
ignores:
- ':matches(code, pre)'
- code
- pre
- blockquote
- img
sources:
- 'README.md'
- 'FAQ.md'
- 'docs/**'
-54
View File
@@ -1,54 +0,0 @@
ACLs
Autoloading
CAS
Customizable
ElastiCache
FPM
GC
IANA
Lua
PSR
Packagist
PhpRedis
Predis
README
Redis
SHA
SSL
TCP
OSS
CLI
TLS
URI
autoload
autoloader
autoloading
backend
backends
behaviour
customizable
dataset
de
DevOPS
extensibility
keyspace
keyspaces
localhost
namespace
pipelining
pluggable
rebalanced
rebalancing
redis
runtime
sharding
stunnel
variadic
commitish
Kubernetes
programmatically
unhandled
invalidations
Sharded
sharded
Valkey
+23 -1
View File
@@ -7,7 +7,6 @@ on:
branches:
- main
- v2.**
- v3.**
pull_request: null
permissions: {}
@@ -144,6 +143,29 @@ jobs:
echo "EXPECTED=${EXPECTED}"
test "${CURRENT}" = "${EXPECTED}"
spelling:
name: Spelling
needs:
- byte_level
- syntax_errors
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Cache pip
uses: actions/cache@v3
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-codespell
- name: Install codespell
run: pip install --user 'codespell>=2.2'
- name: Search for misspellings
run: $(python -m site --user-base)/bin/codespell
changelog:
name: Changelog
-9
View File
@@ -4,24 +4,15 @@ on:
push:
branches:
- main
- v2.**
- v3.**
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
update_release_draft:
permissions:
contents: write
pull-requests: write
name: Update release draft
runs-on: ubuntu-latest
-14
View File
@@ -1,14 +0,0 @@
name: spellcheck
on:
pull_request:
jobs:
check-spelling:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Check Spelling
uses: rojopolis/spellcheck-github-actions@0.33.1
with:
config_path: .github/spellcheck-settings.yml
task_name: Markdown
+23 -41
View File
@@ -5,7 +5,6 @@ on:
branches:
- main
- v2.**
- v3.**
pull_request:
concurrency:
@@ -28,10 +27,10 @@ jobs:
- '8.4'
redis:
- '4.0'
- '6.2'
- '7.2'
- '7.4'
- '8.0'
- '8.2'
steps:
@@ -39,16 +38,17 @@ jobs:
run: |
# Mapping of original redis versions to client test containers
declare -A redis_clients_version_mapping=(
["8.2"]="8.2"
["8.0"]="8.0.2"
["8.0"]="8.0-RC2-pre"
["7.4"]="7.4.2"
["7.2"]="7.2.7"
["6.2"]="6.2.17"
)
# Mapping of redis version to stack version
declare -A redis_stack_version_mapping=(
["7.4"]="rs-7.4.0-v3"
["7.2"]="rs-7.2.0-v15"
["6.2"]="rs-6.2.6-v19"
)
if [[ -v redis_clients_version_mapping[${{ matrix.redis }}] ]]; then
@@ -80,17 +80,10 @@ jobs:
compose-file: .github/docker-compose.yml
services: ${{ env.DOCKER_SERVICE }}
- name: Start Redis unprotected image
uses: hoverkraft-tech/compose-action@v2.0.1
if: ${{ matrix.redis > '4.0' }}
with:
compose-file: .github/docker-compose.yml
services: redis-unprotected
- name: Start Redis stack image
id: stack_infra
uses: hoverkraft-tech/compose-action@v2.0.1
if: ${{ matrix.redis >= '7.2' && matrix.redis < '8.0' }}
if: ${{ matrix.redis >= '6.2' && matrix.redis < '8.0' }}
with:
compose-file: .github/docker-compose.yml
services: redis-stack
@@ -108,7 +101,7 @@ jobs:
with:
php-version: ${{ matrix.php }}
extensions: relay
coverage: ${{ (matrix.php == '8.4' && matrix.redis == '8.0') && 'xdebug' || 'none' }}
coverage: ${{ (matrix.php == '8.4' && matrix.redis == '7.4') && 'xdebug' || 'none' }}
- name: Install Composer dependencies
uses: ramsey/composer-install@v2
@@ -117,74 +110,63 @@ jobs:
composer-options: ${{ matrix.php == '8.0' && '--ignore-platform-reqs' || '' }}
- name: Run tests
if: ${{ matrix.php != '8.4' || matrix.redis != '8.0' }}
if: ${{ matrix.php != '8.4' || matrix.redis != '7.4' }}
run: vendor/bin/phpunit
- name: Run tests with coverage
if: ${{ matrix.php == '8.4' && matrix.redis == '8.0' }}
if: ${{ matrix.php == '8.4' && matrix.redis == '7.4' }}
run: vendor/bin/phpunit --coverage-php build/cov/coverage-predis.cov --coverage-filter ./src
- name: Run tests using Relay
if: ${{ matrix.php != '8.4' && matrix.redis >= '8.0' }}
if: ${{ matrix.php != '8.4' && matrix.redis >= '6.2' }}
run: vendor/bin/phpunit -c phpunit.relay.xml
- name: Run tests using Relay with coverage
if: ${{ matrix.php == '8.4' && matrix.redis == '8.0' }}
if: ${{ matrix.php == '8.4' && matrix.redis == '7.4' }}
run: vendor/bin/phpunit -c phpunit.relay.xml --coverage-php build/cov/coverage-relay.cov --coverage-filter ./src
- name: Run tests against unprotected Redis
if: ${{ (matrix.php != '8.4' || matrix.redis != '8.0') && matrix.redis > '4.0'}}
run: vendor/bin/phpunit --group unprotected
- name: Run tests against unprotected Redis with coverage
if: ${{ matrix.php == '8.4' && matrix.redis == '8.0' }}
run: vendor/bin/phpunit --group unprotected --coverage-php build/cov/coverage-unprotected.cov --coverage-filter ./src
- name: Run stack tests
if: ${{ (matrix.php != '8.4' || matrix.redis != '8.0') && matrix.redis >= '7.2' }}
if: ${{ (matrix.php != '8.4' || matrix.redis != '7.4') && matrix.redis >= '6.2' }}
run: vendor/bin/phpunit --group realm-stack
- name: Run stack tests with coverage
if: ${{ matrix.php == '8.4' && matrix.redis == '8.0' }}
if: ${{ matrix.php == '8.4' && matrix.redis == '7.4' && steps.stack_infra.conclusion == 'success' }}
run: vendor/bin/phpunit --group realm-stack --coverage-php build/cov/coverage-stack.cov --coverage-filter ./src
env:
REDIS_STACK_SERVER_PORT: 6479
- name: Run stack tests using Relay
if: ${{ (matrix.php != '8.4' || matrix.redis != '8.0') && matrix.redis >= '7.2' }}
if: ${{ matrix.php != '8.4' && matrix.redis == '7.4' }}
run: vendor/bin/phpunit --group realm-stack -c phpunit.relay.xml
- name: Run stack tests using Relay with coverage
if: ${{ matrix.php == '8.4' && matrix.redis == '8.0' }}
if: ${{ matrix.php == '8.4' && matrix.redis == '7.4' }}
run: vendor/bin/phpunit --group realm-stack -c phpunit.relay.xml --coverage-php build/cov/coverage-stack-relay.cov --coverage-filter ./src
env:
REDIS_STACK_SERVER_PORT: 6479
- name: Run tests against cluster
if: ${{ (matrix.php != '8.4' || matrix.redis != '8.0') && steps.cluster_infra.conclusion == 'success' }}
if: ${{ (matrix.php != '8.4' || matrix.redis != '7.4') && steps.cluster_infra.conclusion == 'success' }}
run: |
vendor/bin/phpunit --group cluster
- name: Run tests against cluster with coverage
if: ${{ matrix.php == '8.4' && matrix.redis == '8.0' && steps.cluster_infra.conclusion == 'success' }}
if: ${{ matrix.php == '8.4' && matrix.redis == '7.4' && steps.cluster_infra.conclusion == 'success' }}
run: |
vendor/bin/phpunit --group cluster --coverage-php build/cov/coverage-cluster.cov --coverage-filter ./src
- name: Run tests against cluster using Relay
if: ${{ matrix.php != '8.4' && matrix.redis == '8.0' }}
if: ${{ matrix.php != '8.4' && matrix.redis == '7.4' }}
run: |
sleep 5
vendor/bin/phpunit -c phpunit.relay.xml --group cluster
- name: Run tests against cluster using Relay with coverage
if: ${{ matrix.php == '8.4' && matrix.redis == '8.0' }}
run: |
sleep 5
vendor/bin/phpunit -c phpunit.relay.xml --group cluster --coverage-php build/cov/coverage-cluster-relay.cov --coverage-filter ./src
- name: Merge coverage reports
if: ${{ matrix.php == '8.4' && matrix.redis == '8.0' }}
if: ${{ matrix.php == '8.4' && matrix.redis == '7.4' }}
run: php vendor/bin/phpcov merge --clover build/logs/clover.xml build/cov
- name: Send coverage to Coveralls
uses: coverallsapp/github-action@v2
if: ${{ matrix.php == '8.4' && matrix.redis == '8.0' }}
if: ${{ matrix.php == '8.4' && matrix.redis == '7.4' }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
parallel: true
+33 -70
View File
@@ -1,75 +1,9 @@
## Changelog
## Unreleased
### Added
### Changed
### Maintenance
## v3.2.0 (2025-08-05)
### Added
- Added support for `XDELEX` and `XACKDEL` (#1580)
- Added missing VSIM argument (#1582)
### Changed
- Extended `XTRIM` and `XADD` commands with new parameters (#1580)
### Maintenance
- Updated Redis 8.2 test image (#1583)
- Added test coverage for updated Vamana (#1584)
## v3.1.0 (2025-07-22)
### Added
- Add experimental support for vector sets commands (#1550)
- Added support for `XACK` command (#1555)
- Added support for `XCLAIM` command (#1557)
- Added support for `XPENDING` command (#1558)
- Added support for `XSETID` command (#1559)
- Added validation and support for the new `BITOP` command operations (#1566)
### Changed
- Handle and retry `LOADING` errors from Sentinel replicas (#1536)
- Retry all exceptions from Sentinel replicas (#1577)
## v2.4.1 (2025-11-12)
### Fixed
- Fixed PHP 8.4 deprecated call to `stream_context_set_option()` (#1545)
- Fixed return type for `ZCOUNT` to be `int` (#1547)
- Fixed throwing `CommunicationException` when stream is EOF (#1548)
- Removed automatic `conn_uid` parameter assignment (#1552)
- Fixed wrong command API call on prefix processing (#1554)
- Fixed `XREAD` response parsing while read null (#1563)
- Fixed `XINFO` command responses parsing (#1560)
- Marked missing commands as Prefixable (#1576)
## v3.0.1 (2025-05-16)
### Fixed
- Send `default` user if only password is used for authentication (#1535)
## v3.0.0 (2025-05-02)
### Added
- ⚠️ Added support for transactions for clustered connections (#1497)
- Added support for RESP3 communication protocol (#1047)
- Added support for RESP3 push notifications (#1316)
- Added support for Sharded Pub/Sub (#1303)
- Added support for `XGROUP` commands (#1324)
- Added support for `XREADGROUP` command (#1327)
- Added support for `XAUTOCLAIM` command (#1328)
- Added support for `XINFO` commands (#1331)
- Added support for Redis 7.4 `XREAD` and `HSCAN` interface changes (#1452)
### Changed
- ⚠️ Refactored Relay integration (#1423)
- ⚠️ Changed interface of `CLIENT` command (#1337)
- ⚠️ Changed interfaces for commands to support Redis 6.2 — 7.0 arguments (#1330)
- ⚠️ Changed default search `DIALECT` to `2` (#1516)
- ⚠️ Implemented PSR-7 compatible stream abstraction (#1450)
- ⚠️ Improved pipeline abstractions (#1438)
- ⚠️ Improved connection handshake (#1431)
### Fixed
- Fixed single persistent connection using the same resource (#1512)
### Maintenance
- Revisit incompatible tests against Relay (#1537)
- Fixed return type for `ZCOUNT` to be `int` (#1546)
- Removed automatic `conn_uid` parameter assignment (#1551)
## v2.4.0 (2025-04-30)
### Added
@@ -106,7 +40,36 @@
- Filter out available replicas based on link status flag (#1440)
- Respect `prefix` for `ZPOPMIN`, `ZPOPMAX`, `ZMSCORE`, `LMOVE`, `BLMOVE`, `SMISMEMBER` and `GEOSEARCH` (#1451, #1453, #1455, #1468)
- Updated test infrastructure (#1510)
-
### Fixed
- Fixed Relay support when using Redis Cluster (#1397)
- Fixed `cmsincrby()` type annotation (#1333)
- Fixed `set()` type annotation (#1394)
- Fixed operator precedence in connection factory (#1405)
- Fixed a bug with `null` arguments in `set()` method (#1470, #1471)
## v2.2.2 (2023-09-13)
### Added
- Added `client_info` client parameter
- Added support for `CLUSTER` container command
### Fixed
- Fixed `EXPIRETIME` not using `prefix`
- Disabled `CLIENT SETINFO` calls by default
## v2.2.1 (2023-08-15)
### Added
- Added support for `WAITAOF` command (#1357)
- Added support for `SHUTDOWN` command (#1359)
- Added support for `FUNCTION` command (#1332)
- Added support for new optional `PEXPIRE`, `PEXPIREAT` and `COMMAND`
- Added missing Redis Stack commands to `KeyPrefixProcessor` (#1358)
### Changed
- Set client name and version when establishing a connection (#1347)
## v2.2.0 (2023-06-14)
Predis v2.2.0 introduces official support for [Redis Stack](https://redis.io/docs/stack/) as well as a [Relay](https://github.com/cachewerk/relay) integration for substantially [faster read performance](https://github.com/predis/predis/wiki/Using-Relay).
-182
View File
@@ -203,7 +203,6 @@ when needed. The client options supported by default in Predis are:
- `aggregate`: configures the client with a custom aggregate connection (callable).
- `parameters`: list of default connection parameters for aggregate connections.
- `commands`: specifies a command factory instance to use through the library.
- `readTimeout`: (cluster only) Timeout between read operations while loop over connections.
Users can also provide custom options with values or callable objects (for lazy initialization) that
are stored in the options container for later use through the library.
@@ -245,26 +244,6 @@ $options = ['cluster' => 'redis'];
$client = new Predis\Client($parameters, $options);
```
#### Redis Gears with cluster ####
Since Redis v7.2, Redis Gears module is a part of Redis Stack bundle. Client supports a variety of
Redis Gears commands that can be used with OSS cluster API. Currently, before using any Redis
Gears commands against OSS cluster Redis server needs to be aware of cluster topology.
`REDISGEARS_2.REFRESHCLUSTER` command should be called against **each master node** (read replicas
should be ignored) **on cluster creation and each time cluster topology changes**.
In most cases this actions should be performed from the CLI interface by the administrator, DevOPS
or even Kubernetes, depends on your infrastructure managing process. However, client provides an API
to do this programmatically.
```php
/** @var \Predis\Connection\Cluster\ClusterInterface $connection */
$connection->executeCommandOnEachNode(
new \Predis\Command\RawCommand('REDISGEARS_2.REFRESHCLUSTER')
);
```
#### Replication ####
The client can be configured to operate in a single master / multiple slaves setup to provide better
@@ -380,25 +359,6 @@ This abstraction can perform check-and-set operations thanks to `WATCH` and `UNW
automatic retries of transactions aborted by Redis when `WATCH`ed keys are touched. For an example
of a transaction using CAS you can see [the following example](examples/transaction_using_cas.php).
#### Support for clustered connections ####
Since Predis v3.0 transactions could be used with clustered connections. However, it has some limitations due to the
fact that Redis doesn't support distributed transactions. All keys in the transaction context should operate on the same
hash slot, due to this limitation it's recommended to use `{}` syntax to make sure that all keys will be mapped to the same hash
slot. Apart from it no additional configuration needed on a client side.
```php
$redis = $this->getClient();
$response = $redis->transaction(function (MultiExec $tx) {
$tx->set('{foo}foo', 'value');
$tx->set('{foo}bar', 'value');
$tx->set('{foo}baz', 'value');
});
// ['OK', 'OK', 'OK']
```
### Adding new commands ###
@@ -509,149 +469,7 @@ $client = new Predis\Client('tcp://127.0.0.1', [
For a more in-depth insight on how to create new connection backends you can refer to the actual
implementation of the standard connection classes available in the `Predis\Connection` namespace.
## RESP3 ##
### Connection ###
To establish the connection using the [RESP3](https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md) protocol, you need to set parameter `protocol => 3`. The default protocol is RESP2.
You can pass parameter as configuration option in array or as a query parameter in `redis_url`
```php
// Configuration option
$client = new \Predis\Client(['protocol' => 3]);
// Redis URL
$client = new \Predis\Client('redis://localhost:6379?protocol=3');
// ["proto" => "3"]
$client->executeRaw(['HELLO']);
```
### Command responses ###
RESP3 protocol introduce a variety of new [response types](https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md#resp3-types),
so on the client-side we have more explicit understanding on data types we retrieve from server. Here's some examples to show the difference
between RESP2 and RESP3 responses.
#### Float responses ####
``` php
// RESP2 connection
$client = new \Predis\Client();
$client->geoadd('my_geo', 11.111, 22.222, 'member1');
// [[0 => string(20) "11.11099988222122192", 1 => string(20) "22.22200052541037252"]]
// RESP2 returns float values as simple strings.
var_dump($client->geopos('my_geo', ['member1']));
// RESP3 connection
$client = new \Predis\Client(['protocol' => 3]);
// [[0 => float(11.110999882221222), 1 => float(22.222000525410373)]]
// RESP3 introduces new double type, that corresponds to PHP float.
var_dump($client->geopos('my_geo', ['member1']));
```
#### Aggregate types ####
In RESP3 new aggregate type [Map](https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md#map-type)
was introduced, that represents the sequence of field-value pairs. So it simplifies parsing, since we don't need to specify
parsing strategy per command (RESP2) and instead relies on the type defined by protocol (RESP3).
In most cases RESP2 responses shouldn't differ from RESP3, since we added additional parsing for those
command that return field-value pairs. However, since RESP2 requires additional parsing, it could be that some commands
had lack of it and return unhandled responses. In this case there would be difference like this:
```php
$client = new \Predis\Client();
// RESP2: ['field', 'value]
$client->commandThatReturnsFieldValuePair('key');
$client = new \Predis\Client(['protocol' => 3]);
// RESP3: ['field' => 'value]
$client->commandThatReturnsFieldValuePair('key');
```
Feel free to open PR or GitHub issue if you face those protocol mismatching.
### Push notifications ###
RESP3 introduce a concept of [push connection](https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md#push-type),
is the one where server could send asynchronous data to client which was not explicitly requested. Predis 3.0 provides
an API to establish this kind of connection as separate blocking process (worker) and invoke callbacks depends on push
notification message type.
#### Consumer ####
First of all, you need to set up a consumer connection and provide an optional callback that will be executed before
event loop will be started. It allows you to subscribe on channels, enable keys invalidations tracking or enable monitor
connection, any Redis command to let server know that you want to receive push notification within this connection.
```php
// Make sure that RESP3 protocol enabled and read_write_timeout set 0,
// so connection won't be killed by timeout.
$client = new Predis\Client(['read_write_timeout' => 0, 'protocol' => 3]);
// Create push notifications consumer.
// Provides callback where current consumer subscribes to few channels before
// enter the loop.
$push = $client->push(static function (ClientInterface $client) {
$response = $client->subscribe('channel', 'control');
$status = ($response[2] === 1) ? 'OK' : 'FAILED';
echo "Channel subscription status: {$status}\n";
});
```
#### Dispatcher loop ####
Dispatcher object allows you to attach a callback to given push notification type and run the actual worker process that
listen for incoming push notifications. To be able to stop blocking process in runtime you can specify a condition and
call `$dispatcher->stop()` method from given callback. In this example we're waiting for specific message `terminate`
within `control` channel that we subscribed to before entering the loop.
```php
// Storage for incoming notifications.
$messages = [];
// Create dispatcher for push notifications.
$dispatcher = new Predis\Consumer\Push\DispatcherLoop($push);
$dispatcher->attachCallback(
PushResponseInterface::MESSAGE_DATA_TYPE,
static function (array $payload, DispatcherLoopInterface $dispatcher) {
global $messages;
[$channel, $message] = $payload;
if ($channel === 'control' && $message === 'terminate') {
echo "Terminating notification consumer.\n";
$dispatcher->stop();
return;
}
$messages[] = $message;
echo "Received message: {$message}\n";
}
);
// Run consumer loop with attached callbacks.
$dispatcher->run();
// Count all messages that were received during consumer loop.
$messagesCount = count($messages);
echo "We received: {$messagesCount} messages\n";
```
This example shows a simple script to count all incoming messages from push notifications that we receive from
subscribed channels until stop condition will be met. Examples available in `examples/` folder.
### Sharded pub/sub ###
From Redis 7.0, sharded Pub/Sub is introduced in which shard channels are assigned to slots by the same algorithm used
to assign keys to slots.
Predis 3.0 provides an API that allows to use pub/sub for Cluster connections using sharded pub/sub from Redis.
You don't need to specify any additional configuration to enable sharded pub/sub, it will be automatically enabled if
Cluster connection is using.
Implementation looks pretty much the same as Push notification, so you need to set up consumer
and run it over Dispatcher loop object. All examples available in `examples/` folder.
## Development ##
+1 -1
View File
@@ -1 +1 @@
3.2.0
2.4.0
+1 -1
View File
@@ -15,7 +15,7 @@
// For example, to generate a test case for SET (which is represented by the
// Predis\Command\Redis\StringSet class):
//
// $ ./bin/create-command-test --class=StringSet
// $ ./bin/generate-command-test --class=StringSet
//
// Here is a list of optional arguments:
//
+2 -3
View File
@@ -22,13 +22,12 @@
}
],
"require": {
"php": "^7.2 || ^8.0",
"psr/http-message": "^1.0|^2.0"
"php": "^7.2 || ^8.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.3",
"phpstan/phpstan": "^1.9",
"phpunit/phpunit": "^8.0 || ~9.4.4",
"phpunit/phpunit": "^8.0 || ^9.4",
"phpunit/phpcov": "^6.0 || ^8.0"
},
"suggest": {
+1 -1
View File
@@ -30,7 +30,7 @@ $client = new Predis\Client($single_server + ['read_write_timeout' => 0]);
$pubsub = $client->pubSubLoop();
// Create a dispatcher loop instance and attach a bunch of callbacks.
$dispatcher = new Predis\Consumer\PubSub\DispatcherLoop($pubsub);
$dispatcher = new Predis\PubSub\DispatcherLoop($pubsub);
// Demonstrate how to use a callable class as a callback for the dispatcher loop.
class EventsListener implements Countable
-49
View File
@@ -1,49 +0,0 @@
<?php
/*
* This file is part of the Predis package.
*
* (c) 2009-2020 Daniele Alessandri
* (c) 2021-2025 Till Krüss
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Predis\ClientInterface;
use Predis\Consumer\Push\PushResponseInterface;
require __DIR__ . '/shared.php';
// 1. Create client with RESP3 protocol specified. Push notifications allowed only in RESP3 mode.
$client = new Predis\Client($single_server + ['read_write_timeout' => 0, 'protocol' => 3]);
// 2. Create push notifications consumer. Provides callback where current consumer subscribes to few channels before enter the loop.
$push = $client->push(static function (ClientInterface $client) {
$response = $client->subscribe('channel', 'control');
$status = ($response[2] === 1) ? 'OK' : 'FAILED';
echo "Channel subscription status: {$status}\n";
});
// 3. Run consumer that will handle message data type push notifications. And stops if certain message will be sent to control channel.
// Send following commands via redis-cli to test:
//
// PUBLISH channel message1
// PUBLISH channel message2
// PUBLISH channel message3
// PUBLISH control terminate
// Data types should be changed in near future. Instead of Message data type it should be one of kind data types.
foreach ($push as $notification) {
if ((null !== $notification) && $notification->getDataType() === PushResponseInterface::MESSAGE_DATA_TYPE) {
if ($notification[1] === 'control' && $notification[2] === 'terminate') {
echo "Terminating notification consumer.\n";
$push->stop();
break;
}
$message = $notification[2];
echo "Received message: {$message}\n";
}
}
@@ -1,68 +0,0 @@
<?php
/*
* This file is part of the Predis package.
*
* (c) 2009-2020 Daniele Alessandri
* (c) 2021-2025 Till Krüss
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Predis\ClientInterface;
use Predis\Consumer\DispatcherLoopInterface;
use Predis\Consumer\Push\DispatcherLoop;
use Predis\Consumer\Push\PushResponseInterface;
require __DIR__ . '/shared.php';
// 1. Create client with RESP3 protocol specified. Push notifications allowed only in RESP3 mode.
$client = new Predis\Client($single_server + ['read_write_timeout' => 0, 'protocol' => 3]);
// 2. Create push notifications consumer. Provides callback where current consumer subscribes to few channels before enter the loop.
$push = $client->push(static function (ClientInterface $client) {
$response = $client->subscribe('channel', 'control');
$status = ($response[2] === 1) ? 'OK' : 'FAILED';
echo "Channel subscription status: {$status}\n";
});
// 3. Storage for upcoming notifications.
$messages = [];
// 4. Create dispatcher for push notifications.
$dispatcher = new DispatcherLoop($push);
// 5. Attach callback for message data type. Print every message and store them in storage.
// Send following commands via redis-cli to test:
//
// PUBLISH channel message1
// PUBLISH channel message2
// PUBLISH channel message3
// PUBLISH control terminate
// Data types should be changed in near future. Instead of Message data type it should be one of kind data types.
$dispatcher->attachCallback(
PushResponseInterface::MESSAGE_DATA_TYPE,
static function (array $payload, DispatcherLoopInterface $dispatcher) {
global $messages;
[$channel, $message] = $payload;
if ($channel === 'control' && $message === 'terminate') {
echo "Terminating notification consumer.\n";
$dispatcher->stop();
return;
}
$messages[] = $message;
echo "Received message: {$message}\n";
}
);
// 6. Run consumer loop with attached callbacks.
$dispatcher->run();
// 7. Count all messages that were received during consumer loop.
$messagesCount = count($messages);
echo "We received: {$messagesCount} messages\n";
-91
View File
@@ -1,91 +0,0 @@
<?php
/*
* This file is part of the Predis package.
*
* (c) 2009-2020 Daniele Alessandri
* (c) 2021-2025 Till Krüss
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Predis\Client;
require __DIR__ . '/shared.php';
// This is a basic example on how to use the Predis\DispatcherLoop class in sharded pub/sub mode.
//
// Both channels belong to different shards. So in sharded mode we can subscribe
// and receive messages from different shard channels.
//
// To see this example in action you can just use redis-cli and publish some
// messages to the '{channels}_events' and 'control' channel, e.g.:
// ./redis-cli
// SPUBLISH {channels}_events first
// SPUBLISH {channels}_events second
// SPUBLISH {channels}_events third
// SPUBLISH control terminate_dispatcher
// 1. Create client and setup RW timeout to 0.
$client = new Client(
[
'tcp://127.0.0.1:6372?read_write_timeout=0',
'tcp://127.0.0.1:6373?read_write_timeout=0',
'tcp://127.0.0.1:6374?read_write_timeout=0',
], [
'cluster' => 'redis',
]);
// 2. Run pub/sub loop.
$pubSub = $client->pubSubLoop();
// 3. Create a dispatcher loop instance and attach a bunch of callbacks.
$dispatcher = new Predis\Consumer\PubSub\DispatcherLoop($pubSub);
// 4. Demonstrate how to use a callable class as a callback for the dispatcher loop.
class EventsListener implements Countable
{
private $events;
public function __construct()
{
$this->events = [];
}
public function count()
{
return count($this->events);
}
public function getEvents()
{
return $this->events;
}
public function __invoke($payload, $dispatcher)
{
$this->events[] = $payload;
}
}
// 5. Attach our callable class to the dispatcher.
$dispatcher->attachCallback('{channels}_events', $events = new EventsListener());
// 6. Attach a function to control the dispatcher loop termination with a message.
$dispatcher->attachCallback('control', function ($payload, $dispatcher) {
if ($payload === 'terminate_dispatcher') {
$dispatcher->stop();
}
});
// 7. Run the dispatcher loop until the callback attached to the 'control' channel
// receives 'terminate_dispatcher' as a message.
$dispatcher->run();
// Display our achievements!
echo "We received {$events->count()} messages!", PHP_EOL;
// Say goodbye :-)
echo 'Goodbye from Redis!', PHP_EOL;
-64
View File
@@ -1,64 +0,0 @@
<?php
/*
* This file is part of the Predis package.
*
* (c) 2009-2020 Daniele Alessandri
* (c) 2021-2025 Till Krüss
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Predis\Client;
require __DIR__ . '/shared.php';
// 1. Create client and setup RW timeout to 0.
$client = new Client(
[
'tcp://127.0.0.1:6372?read_write_timeout=0',
'tcp://127.0.0.1:6373?read_write_timeout=0',
'tcp://127.0.0.1:6374?read_write_timeout=0',
], [
'cluster' => 'redis',
]);
// 2. Run pub/sub loop. Sharded channels belongs to different shards.
$pubSub = $client->pubSubLoop();
$pubSub->ssubscribe('{channels}_notifications');
$pubSub->ssubscribe('control_channel');
// Start processing the pubsup messages. Open a terminal and use redis-cli
// to push messages to the channels. Examples:
// ./redis-cli SPUBLISH {channels}_notifications "this is a test"
// ./redis-cli SPUBLISH control_channel quit_loop
foreach ($pubSub as $message) {
switch ($message->kind) {
case 'ssubscribe':
echo "Subscribed to {$message->channel}", PHP_EOL;
break;
case 'message':
if ($message->channel == 'control_channel') {
if ($message->payload == 'quit_loop') {
echo 'Aborting pubsub loop...', PHP_EOL;
$pubSub->sunsubscribe();
} else {
echo "Received an unrecognized command: {$message->payload}.", PHP_EOL;
}
} else {
echo "Received the following message from {$message->channel}:",
PHP_EOL, " {$message->payload}", PHP_EOL, PHP_EOL;
}
break;
}
}
// Always unset the pubsub consumer instance when you are done! The
// class destructor will take care of cleanups and prevent protocol
// desynchronizations between the client and the server.
unset($pubsub);
// Say goodbye :-)
echo 'Goodbye from Redis!', PHP_EOL;
+6
View File
@@ -12,6 +12,9 @@ parameters:
- message: "#^Cannot cast Predis\\\\Connection\\\\ConnectionInterface to string\\.$#"
count: 1
path: src/Client.php
# phpiredis extension is not installed
- "#^Function phpiredis_\\w+ not found\\.$#"
- "#^Constant PHPIREDIS_#"
# "new static" in non-final classes
- message: "#^Unsafe usage of new static\\(\\)\\.$#"
count: 3
@@ -26,6 +29,9 @@ parameters:
- message: "#^Call to an undefined method Predis\\\\Command\\\\FactoryInterface\\:\\:undefine\\(\\)\\.$#"
count: 1
path: src/Configuration/Option/Commands.php
- message: "#^Access to an undefined property Predis\\\\Configuration\\\\OptionsInterface\\:\\:\\$parameters\\.$#"
count: 1
path: src/Configuration/Option/Connections.php
- message: "#^Access to an undefined property Predis\\\\Connection\\\\ParametersInterface\\:\\:\\$weight\\.$#"
count: 1
path: src/Connection/Cluster/PredisCluster.php
+3 -12
View File
@@ -17,19 +17,15 @@
</testsuite>
</testsuites>
<logging>
<log type="coverage-php" target="build/cov/coverage.cov"/>
</logging>
<groups>
<exclude>
<group>relay-incompatible</group>
<group>relay-resp3</group>
<group>realm-webdis</group>
<group>realm-stack</group>
<group>ext-curl</group>
<group>ext-phpiredis</group>
<group>cluster</group>
<group>gears</group>
<group>unprotected</group>
</exclude>
</groups>
@@ -42,17 +38,12 @@
<php>
<const name="REDIS_SERVER_HOST" value="127.0.0.1" />
<const name="REDIS_SERVER_PORT" value="6379" />
<const name="REDIS_UNPROTECTED_SERVER_PORT" value="6380" />
<const name="REDIS_SERVER_DBNUM" value="0" />
<const name="REDIS_PASSWORD" value="foobar" />
<env name="USE_RELAY" value="true" />
<env name="REDIS_STACK_SERVER_PORT" value="6479" />
<!-- Redis Cluster -->
<!-- Only master nodes endpoints included -->
<const
name="REDIS_CLUSTER_ENDPOINTS"
value="127.0.0.1:6372?password=foobar,127.0.0.1:6373?password=foobar,127.0.0.1:6374?password=foobar"
/>
<const name="REDIS_CLUSTER_ENDPOINTS" value="127.0.0.1:6372,127.0.0.1:6373,127.0.0.1:6374" />
</php>
</phpunit>
+11 -15
View File
@@ -10,9 +10,6 @@
stopOnFailure="false"
beStrictAboutTestsThatDoNotTestAnything="true"
>
<php>
<ini name="error_reporting" value="E_ALL &amp; ~E_DEPRECATED"/>
</php>
<testsuites>
<testsuite name="Predis Test Suite">
@@ -20,19 +17,23 @@
</testsuite>
</testsuites>
<logging>
<log type="coverage-php" target="build/cov/coverage.cov"/>
</logging>
<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">./src</directory>
</include>
<report>
<clover outputFile="build/logs/clover.xml"/>
</report>
</coverage>
<groups>
<exclude>
<group>realm-webdis</group>
<group>realm-stack</group>
<group>ext-relay</group>
<group>ext-curl</group>
<group>ext-phpiredis</group>
<group>cluster</group>
<group>gears</group>
<group>gears-cluster</group>
<group>unprotected</group>
<!-- <group>connected</group> -->
<!-- <group>disconnected</group> -->
<!-- <group>commands</group> -->
@@ -49,17 +50,12 @@
<php>
<const name="REDIS_SERVER_HOST" value="127.0.0.1" />
<const name="REDIS_SERVER_PORT" value="6379" />
<const name="REDIS_UNPROTECTED_SERVER_PORT" value="6380" />
<const name="REDIS_SERVER_DBNUM" value="0" />
<const name="REDIS_PASSWORD" value="foobar" />
<env name="USE_RELAY" value="false" />
<env name="REDIS_STACK_SERVER_PORT" value="6479" />
<!-- Redis Cluster -->
<!-- Only master nodes endpoints included -->
<const
name="REDIS_CLUSTER_ENDPOINTS"
value="127.0.0.1:6372?password=foobar,127.0.0.1:6373?password=foobar,127.0.0.1:6374?password=foobar"
/>
<const name="REDIS_CLUSTER_ENDPOINTS" value="127.0.0.1:6372,127.0.0.1:6373,127.0.0.1:6374" />
</php>
</phpunit>
+6 -23
View File
@@ -16,9 +16,9 @@ use ArrayIterator;
use InvalidArgumentException;
use IteratorAggregate;
use Predis\Command\CommandInterface;
use Predis\Command\Container\ContainerFactory;
use Predis\Command\Container\ContainerInterface;
use Predis\Command\RawCommand;
use Predis\Command\Redis\Container\ContainerFactory;
use Predis\Command\Redis\Container\ContainerInterface;
use Predis\Command\ScriptCommand;
use Predis\Configuration\Options;
use Predis\Configuration\OptionsInterface;
@@ -26,15 +26,14 @@ use Predis\Connection\ConnectionInterface;
use Predis\Connection\Parameters;
use Predis\Connection\ParametersInterface;
use Predis\Connection\RelayConnection;
use Predis\Consumer\PubSub\Consumer as PubSubConsumer;
use Predis\Consumer\PubSub\RelayConsumer as RelayPubSubConsumer;
use Predis\Consumer\Push\Consumer as PushConsumer;
use Predis\Monitor\Consumer as MonitorConsumer;
use Predis\Pipeline\Atomic;
use Predis\Pipeline\FireAndForget;
use Predis\Pipeline\Pipeline;
use Predis\Pipeline\RelayAtomic;
use Predis\Pipeline\RelayPipeline;
use Predis\PubSub\Consumer as PubSubConsumer;
use Predis\PubSub\RelayConsumer as RelayPubSubConsumer;
use Predis\Response\ErrorInterface as ErrorResponseInterface;
use Predis\Response\ResponseInterface;
use Predis\Response\ServerException;
@@ -54,7 +53,7 @@ use Traversable;
*/
class Client implements ClientInterface, IteratorAggregate
{
public const VERSION = '3.2.0';
public const VERSION = '2.4.2-dev';
/** @var OptionsInterface */
private $options;
@@ -380,7 +379,6 @@ class Client implements ClientInterface, IteratorAggregate
public function executeCommand(CommandInterface $command)
{
$response = $this->connection->executeCommand($command);
$parameters = $this->connection->getParameters();
if ($response instanceof ResponseInterface) {
if ($response instanceof ErrorResponseInterface) {
@@ -390,11 +388,7 @@ class Client implements ClientInterface, IteratorAggregate
return $response;
}
if ($parameters->protocol === 2) {
return $command->parseResponse($response);
}
return $command->parseResp3Response($response);
return $command->parseResponse($response);
}
/**
@@ -555,17 +549,6 @@ class Client implements ClientInterface, IteratorAggregate
return $this->sharedContextFactory('createPubSub', func_get_args());
}
/**
* Creates new push notifications consumer.
*
* @param callable|null $preLoopCallback Callback that should be called on client before enter a loop.
* @return PushConsumer
*/
public function push(?callable $preLoopCallback = null): PushConsumer
{
return new PushConsumer($this, $preLoopCallback);
}
/**
* Actual publish/subscribe context initializer method.
*
+19 -50
View File
@@ -38,14 +38,14 @@ use Predis\Command\Argument\TimeSeries\MGetArguments;
use Predis\Command\Argument\TimeSeries\MRangeArguments;
use Predis\Command\Argument\TimeSeries\RangeArguments;
use Predis\Command\CommandInterface;
use Predis\Command\Container\ACL;
use Predis\Command\Container\CLIENT;
use Predis\Command\Container\FUNCTIONS;
use Predis\Command\Container\Json\JSONDEBUG;
use Predis\Command\Container\Search\FTCONFIG;
use Predis\Command\Container\Search\FTCURSOR;
use Predis\Command\Container\XGROUP;
use Predis\Command\Redis\VADD;
use Predis\Command\Redis\Container\ACL;
use Predis\Command\Redis\Container\CLUSTER;
use Predis\Command\Redis\Container\FunctionContainer;
use Predis\Command\Redis\Container\Json\JSONDEBUG;
use Predis\Command\Redis\Container\Search\FTCONFIG;
use Predis\Command\Redis\Container\Search\FTCURSOR;
use Predis\Command\Redis\HGETEX;
use Predis\Command\Redis\HSETEX;
/**
* Interface defining a client-side context such as a pipeline or transaction.
@@ -61,8 +61,8 @@ use Predis\Command\Redis\VADD;
* @method $this move($key, $db)
* @method $this object($subcommand, $key)
* @method $this persist($key)
* @method $this pexpire($key, $milliseconds, string $option = null)
* @method $this pexpireat($key, $timestamp, string $option = null)
* @method $this pexpire($key, $milliseconds)
* @method $this pexpireat($key, $timestamp)
* @method $this pttl($key)
* @method $this randomkey()
* @method $this rename($key, $target)
@@ -242,9 +242,6 @@ use Predis\Command\Redis\VADD;
* @method $this srandmember($key, $count = null)
* @method $this srem($key, $member)
* @method $this sscan($key, $cursor, ?array $options = null)
* @method $this ssubscribe(string ...$shardChannels)
* @method $this subscribe(string ...$channels)
* @method $this sunsubscribe(?string ...$shardChannels = null)
* @method $this sunion(array|string $keys)
* @method $this sunionstore($destination, array|string $keys)
* @method $this tdigestadd(string $key, float ...$value)
@@ -284,21 +281,6 @@ use Predis\Command\Redis\VADD;
* @method $this tsqueryindex(string ...$filterExpression)
* @method $this tsrange(string $key, $fromTimestamp, $toTimestamp, ?RangeArguments $arguments = null)
* @method $this tsrevrange(string $key, $fromTimestamp, $toTimestamp, ?RangeArguments $arguments = null)
* @method $this xack(string $key, string $group, string ...$id)
* @method $this xackdel(string $key, string $group, string $mode, array $ids)
* @method $this xadd(string $key, array $dictionary, string $id = '*', array $options = null)
* @method $this xautoclaim(string $key, string $group, string $consumer, int $minIdleTime, string $start, ?int $count = null, bool $justId = false)
* @method $this xclaim(string $key, string $group, string $consumer, int $minIdleTime, string|array $ids, ?int $idle = null, ?int $time = null, ?int $retryCount = null, bool $force = false, bool $justId = false, ?string $lastId = null)
* @method $this xdel(string $key, string ...$id)
* @method $this xdelex(string $key, string $mode, array $ids)
* @method $this xlen(string $key)
* @method $this xpending(string $key, string $group, ?int $minIdleTime = null, ?string $start = null, ?string $end = null, ?int $count = null, ?string $consumer = null)
* @method $this xrevrange(string $key, string $end, string $start, ?int $count = null)
* @method $this xrange(string $key, string $start, string $end, ?int $count = null)
* @method $this xread(int $count = null, int $block = null, array $streams = null, string ...$id)
* @method $this xreadgroup(string $group, string $consumer, ?int $count = null, ?int $blockMs = null, bool $noAck = false, string ...$keyOrId)
* @method $this xsetid(string $key, string $lastId, ?int $entriesAdded = null, ?string $maxDeleteId = null)
* @method $this xtrim(string $key, array|string $strategy, string $threshold, array $options = null)
* @method $this zadd($key, array $membersAndScoresDictionary)
* @method $this zcard($key)
* @method $this zcount($key, $min, $max)
@@ -340,18 +322,6 @@ use Predis\Command\Redis\VADD;
* @method $this multi()
* @method $this unwatch()
* @method $this waitaof(int $numLocal, int $numReplicas, int $timeout)
* @method $this unsubscribe(string ...$channels)
* @method $this vadd(string $key, string|array $vector, string $elem, int $dim = null, bool $cas = false, string $quant = VADD::QUANT_DEFAULT, ?int $BEF = null, string|array $attributes = null, int $numlinks = null)
* @method $this vcard(string $key)
* @method $this vdim(int $key)
* @method $this vemb(string $key, string $elem, bool $raw = false)
* @method $this vgetattr(string $key, string $elem, bool $asJson = false)
* @method $this vinfo(string $key)
* @method $this vlinks(string $key, string $elem, bool $withScores = false)
* @method $this vrandmember(string $key, int $count = null)
* @method $this vrem(string $key, string $elem)
* @method $this vsetattr(string $key, string $elem, string|array $attributes)
* @method $this vsim(string $key, string|array $vectorOrElem, bool $isElem = false, bool $withScores = false, int $count = null, float $epsilon = null, int $ef = null, string $filter = null, int $filterEf = null, bool $truth = false, bool $noThread = false)
* @method $this watch($key)
* @method $this eval($script, $numkeys, $keyOrArg1 = null, $keyOrArgN = null)
* @method $this eval_ro(string $script, array $keys, ...$argument)
@@ -365,18 +335,18 @@ use Predis\Command\Redis\VADD;
* @method $this select($database)
* @method $this bgrewriteaof()
* @method $this bgsave()
* @method $this client($subcommand, $argument = null)
* @method $this config($subcommand, $argument = null)
* @method $this dbsize()
* @method $this flushall()
* @method $this flushdb()
* @method $this info(string ...$section = null)
* @method $this info($section = null)
* @method $this lastsave()
* @method $this save()
* @method $this slaveof($host, $port)
* @method $this slowlog($subcommand, $argument = null)
* @method $this spublish(string $shardChannel, string $message)
* @method $this time()
* @method $this command($subcommand, $argument = null)
* @method $this command()
* @method $this geoadd($key, $longitude, $latitude, $member)
* @method $this geohash($key, array $members)
* @method $this geopos($key, array $members)
@@ -387,13 +357,12 @@ use Predis\Command\Redis\VADD;
* @method $this geosearchstore(string $destination, string $source, FromInterface $from, ByInterface $by, ?string $sorting = null, int $count = -1, bool $any = false, bool $storeDist = false)
*
* Container commands
* @property CLIENT $client
* @property FUNCTIONS $function
* @property FTCONFIG $ftconfig
* @property FTCURSOR $ftcursor
* @property JSONDEBUG $jsondebug
* @property ACL $acl
* @property XGROUP $xgroup
* @property CLUSTER $cluster
* @property FunctionContainer $function
* @property FTCONFIG $ftconfig
* @property FTCURSOR $ftcursor
* @property JSONDEBUG $jsondebug
* @property ACL $acl
*/
interface ClientContextInterface
{
+34 -58
View File
@@ -38,16 +38,15 @@ use Predis\Command\Argument\TimeSeries\MGetArguments;
use Predis\Command\Argument\TimeSeries\MRangeArguments;
use Predis\Command\Argument\TimeSeries\RangeArguments;
use Predis\Command\CommandInterface;
use Predis\Command\Container\ACL;
use Predis\Command\Container\CLIENT;
use Predis\Command\Container\FUNCTIONS;
use Predis\Command\Container\Json\JSONDEBUG;
use Predis\Command\Container\Search\FTCONFIG;
use Predis\Command\Container\Search\FTCURSOR;
use Predis\Command\Container\XGROUP;
use Predis\Command\Container\XINFO;
use Predis\Command\FactoryInterface;
use Predis\Command\Redis\VADD;
use Predis\Command\Redis\Container\ACL;
use Predis\Command\Redis\Container\CLUSTER;
use Predis\Command\Redis\Container\FunctionContainer;
use Predis\Command\Redis\Container\Json\JSONDEBUG;
use Predis\Command\Redis\Container\Search\FTCONFIG;
use Predis\Command\Redis\Container\Search\FTCURSOR;
use Predis\Command\Redis\HGETEX;
use Predis\Command\Redis\HSETEX;
use Predis\Configuration\OptionsInterface;
use Predis\Connection\ConnectionInterface;
use Predis\Response\Status;
@@ -71,8 +70,8 @@ use Predis\Response\Status;
* @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, string $option = null)
* @method int pexpireat(string $key, int $timestamp, string $option = null)
* @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)
@@ -83,8 +82,8 @@ use Predis\Response\Status;
* @method int ttl(string $key)
* @method mixed type(string $key)
* @method int append(string $key, $value)
* @method mixed bfadd(string $key, $item)
* @method mixed bfexists(string $key, $item)
* @method int bfadd(string $key, $item)
* @method int bfexists(string $key, $item)
* @method array bfinfo(string $key, string $modifier = '')
* @method array bfinsert(string $key, int $capacity = -1, float $error = -1, int $expansion = -1, bool $noCreate = false, bool $nonScaling = false, string ...$item)
* @method Status bfloadchunk(string $key, int $iterator, $data)
@@ -101,11 +100,11 @@ use Predis\Response\Status;
* @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 mixed cfadd(string $key, $item)
* @method mixed cfaddnx(string $key, $item)
* @method int cfadd(string $key, $item)
* @method int cfaddnx(string $key, $item)
* @method int cfcount(string $key, $item)
* @method mixed cfdel(string $key, $item)
* @method mixed cfexists(string $key, $item)
* @method int cfdel(string $key, $item)
* @method int cfexists(string $key, $item)
* @method Status cfloadchunk(string $key, int $iterator, $data)
* @method int cfmexists(string $key, ...$item)
* @method array cfinfo(string $key)
@@ -203,8 +202,8 @@ use Predis\Response\Status;
* @method array jsonarrtrim(string $key, string $path, int $start, int $stop)
* @method int jsondel(string $key, string $path = '$')
* @method int jsonforget(string $key, string $path = '$')
* @method mixed jsonget(string $key, string $indent = '', string $newline = '', string $space = '', string ...$paths)
* @method mixed jsonnumincrby(string $key, string $path, int $value)
* @method string jsonget(string $key, string $indent = '', string $newline = '', string $space = '', string ...$paths)
* @method string jsonnumincrby(string $key, string $path, int $value)
* @method Status jsonmerge(string $key, string $path, string $value)
* @method array jsonmget(array $keys, string $path)
* @method Status jsonmset(string ...$keyPathValue)
@@ -251,12 +250,9 @@ use Predis\Response\Status;
* @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 array ssubscribe(string ...$shardChannels)
* @method array subscribe(string ...$channels)
* @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 array sunsubscribe(?string ...$shardChannels = null)
* @method int touch(string[]|string $keyOrKeys, string ...$keys = null)
* @method Status tdigestadd(string $key, float ...$value)
* @method array tdigestbyrank(string $key, int ...$rank)
@@ -264,10 +260,10 @@ use Predis\Response\Status;
* @method array tdigestcdf(string $key, int ...$value)
* @method Status tdigestcreate(string $key, int $compression = 0)
* @method array tdigestinfo(string $key)
* @method mixed tdigestmax(string $key)
* @method string tdigestmax(string $key)
* @method Status tdigestmerge(string $destinationKey, array $sourceKeys, int $compression = 0, bool $override = false)
* @method string[] tdigestquantile(string $key, float ...$quantile)
* @method mixed tdigestmin(string $key)
* @method string tdigestmin(string $key)
* @method array tdigestrank(string $key, float ...$value)
* @method Status tdigestreset(string $key)
* @method array tdigestrevrank(string $key, float ...$value)
@@ -295,21 +291,13 @@ use Predis\Response\Status;
* @method array tsqueryindex(string ...$filterExpression)
* @method array tsrange(string $key, $fromTimestamp, $toTimestamp, ?RangeArguments $arguments = null)
* @method array tsrevrange(string $key, $fromTimestamp, $toTimestamp, ?RangeArguments $arguments = null)
* @method int xack(string $key, string $group, string ...$id)
* @method array xackdel(string $key, string $group, string $mode, array $ids)
* @method string xadd(string $key, array $dictionary, string $id = '*', array $options = null)
* @method array xautoclaim(string $key, string $group, string $consumer, int $minIdleTime, string $start, ?int $count = null, bool $justId = false)
* @method array xclaim(string $key, string $group, string $consumer, int $minIdleTime, string|array $ids, ?int $idle = null, ?int $time = null, ?int $retryCount = null, bool $force = false, bool $justId = false, ?string $lastId = null)
* @method string xadd(string $key, array $dictionary, string $id = '*', ?array $options = null)
* @method int xdel(string $key, string ...$id)
* @method array xdelex(string $key, string $mode, array $ids)
* @method int xlen(string $key)
* @method array xpending(string $key, string $group, ?int $minIdleTime = null, ?string $start = null, ?string $end = null, ?int $count = null, ?string $consumer = null)
* @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 array|null xread(int $count = null, int $block = null, array $streams = null, string ...$id)
* @method array xreadgroup(string $group, string $consumer, ?int $count = null, ?int $blockMs = null, bool $noAck = false, string ...$keyOrId)
* @method Status xsetid(string $key, string $lastId, ?int $entriesAdded = null, ?string $maxDeleteId = 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 int zcount(string $key, int|string $min, int|string $max)
@@ -352,18 +340,6 @@ use Predis\Response\Status;
* @method array|null exec()
* @method mixed multi()
* @method mixed unwatch()
* @method array unsubscribe(string ...$channels)
* @method bool vadd(string $key, string|array $vector, string $elem, int $dim = null, bool $cas = false, string $quant = VADD::QUANT_DEFAULT, int $bef = null, string|array $attributes = null, int $numlinks = null)
* @method int vcard(string $key)
* @method int vdim(string $key)
* @method array vemb(string $key, string $elem, bool $raw = false)
* @method string|array|null vgetattr(string $key, string $elem, bool $asJson = false)
* @method array|null vinfo(string $key)
* @method array|null vlinks(string $key, string $elem, bool $withScores = false)
* @method string|array|null vrandmember(string $key, int $count = null)
* @method bool vrem(string $key, string $elem)
* @method array vsim(string $key, string|array $vectorOrElem, bool $isElem = false, bool $withScores = false, int $count = null, float $epsilon = null, int $ef = null, string $filter = null, int $filterEf = null, bool $truth = false, bool $noThread = false)
* @method bool vsetattr(string $key, string $elem, string|array $attributes)
* @method array waitaof(int $numLocal, int $numReplicas, int $timeout)
* @method mixed watch(string[]|string $keyOrKeys)
* @method mixed eval(string $script, int $numkeys, string ...$keyOrArg = null)
@@ -378,18 +354,18 @@ use Predis\Response\Status;
* @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(string ...$section = null)
* @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 int spublish(string $shardChannel, string $message)
* @method array time()
* @method array command($subcommand, $argument = null)
* @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)
@@ -400,14 +376,14 @@ use Predis\Response\Status;
* @method int geosearchstore(string $destination, string $source, FromInterface $from, ByInterface $by, ?string $sorting = null, int $count = -1, bool $any = false, bool $storeDist = false)
*
* Container commands
* @property CLIENT $client
* @property FUNCTIONS $function
* @property FTCONFIG $ftconfig
* @property FTCURSOR $ftcursor
* @property JSONDEBUG $jsondebug
* @property ACL $acl
* @property XGROUP $xgroup
* @property XINFO $xinfo
* @property CLUSTER $cluster
* @property FunctionContainer $function
* @property FTCONFIG $ftconfig
* @property FTCURSOR $ftcursor
* @property JSONDEBUG $jsondebug
* @property ACL $acl
*
* @no-named-arguments
*/
interface ClientInterface
{
+8 -25
View File
@@ -177,11 +177,6 @@ abstract class ClusterStrategy implements StrategyInterface
'GEORADIUS' => [$this, 'getKeyFromGeoradiusCommands'],
'GEORADIUSBYMEMBER' => [$this, 'getKeyFromGeoradiusCommands'],
/* sharded pubsub */
'SSUBSCRIBE' => $getKeyFromAllArguments,
'SUNSUBSCRIBE' => [$this, 'getKeyFromSUnsubscribeCommand'],
'SPUBLISH' => $getKeyFromFirstArgument,
/* cluster */
'CLUSTER' => [$this, 'getFakeKey'],
];
@@ -412,24 +407,6 @@ abstract class ClusterStrategy implements StrategyInterface
return $arguments[0];
}
/**
* Extracts key from SUNSUBSCRIBE command if it's given.
*
* @param CommandInterface $command
* @return string
*/
protected function getKeyFromSUnsubscribeCommand(CommandInterface $command): ?string
{
$arguments = $command->getArguments();
// SUNSUBSCRIBE command could be called without arguments, so it doesn't matter on each node it will be called.
if (empty($arguments)) {
return 'fake';
}
return $this->getKeyFromAllArguments($command);
}
/**
* Extracts the key from EVAL and EVALSHA commands.
*
@@ -470,9 +447,13 @@ abstract class ClusterStrategy implements StrategyInterface
}
/**
* {@inheritdoc}
* Checks if the specified array of keys will generate the same hash.
*
* @param array $keys Array of keys.
*
* @return bool
*/
public function checkSameSlotForKeys(array $keys): bool
protected function checkSameSlotForKeys(array $keys)
{
if (!$count = count($keys)) {
return false;
@@ -486,6 +467,8 @@ abstract class ClusterStrategy implements StrategyInterface
if ($currentSlot !== $nextSlot) {
return false;
}
$currentSlot = $nextSlot;
}
return true;
+42
View File
@@ -0,0 +1,42 @@
<?php
/*
* This file is part of the Predis package.
*
* (c) 2009-2020 Daniele Alessandri
* (c) 2021-2025 Till Krüss
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Predis\Cluster\Hash;
use Predis\NotSupportedException;
/**
* Hash generator implementing the CRC-CCITT-16 algorithm used by redis-cluster.
*
* @deprecated 2.1.2
*/
class PhpiredisCRC16 implements HashGeneratorInterface
{
public function __construct()
{
if (!function_exists('phpiredis_utils_crc16')) {
// @codeCoverageIgnoreStart
throw new NotSupportedException(
'This hash generator requires a compatible version of ext-phpiredis'
);
// @codeCoverageIgnoreEnd
}
}
/**
* {@inheritdoc}
*/
public function hash($value)
{
return phpiredis_utils_crc16($value);
}
}
+3 -1
View File
@@ -46,7 +46,7 @@ class PredisStrategy extends ClusterStrategy
/**
* {@inheritdoc}
*/
public function checkSameSlotForKeys(array $keys): bool
protected function checkSameSlotForKeys(array $keys)
{
if (!$count = count($keys)) {
return false;
@@ -60,6 +60,8 @@ class PredisStrategy extends ClusterStrategy
if ($currentKey !== $nextKey) {
return false;
}
$currentKey = $nextKey;
}
return true;
+1 -1
View File
@@ -66,7 +66,7 @@ class SlotRange implements Countable
*/
public static function isValidRange($first, $last)
{
return $first >= 0x0000 && $first <= self::MAX_SLOTS && $last >= 0x0000 && $last <= self::MAX_SLOTS && $first <= $last;
return $first >= 0 && $first <= self::MAX_SLOTS && $last >= 0x0000 && $last <= self::MAX_SLOTS && $first <= $last;
}
/**
-8
View File
@@ -49,12 +49,4 @@ interface StrategyInterface
* @return DistributorInterface
*/
public function getDistributor();
/**
* Checks if the specified array of keys will generate the same hash.
*
* @param array $keys
* @return bool
*/
public function checkSameSlotForKeys(array $keys): bool;
}
@@ -1,49 +0,0 @@
<?php
/*
* This file is part of the Predis package.
*
* (c) 2009-2020 Daniele Alessandri
* (c) 2021-2025 Till Krüss
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Predis\Command\Argument\Stream;
use Predis\Command\Argument\ArrayableArgument;
class XInfoStreamOptions implements ArrayableArgument
{
/**
* @var array
*/
protected $options = [];
/**
* Modifier provides a more verbose reply.
* The COUNT option can be used to limit the number of stream and PEL entries that are returned.
*
* @param int|null $count
* @return self
*/
public function full(?int $count = null): self
{
$this->options[] = 'FULL';
if (null !== $count) {
array_push($this->options, 'COUNT', $count);
}
return $this;
}
/**
* {@inheritDoc}
*/
public function toArray(): array
{
return $this->options;
}
}
-74
View File
@@ -12,9 +12,6 @@
namespace Predis\Command;
use Predis\ClientConfiguration;
use UnexpectedValueException;
/**
* Base class for Redis commands.
*/
@@ -83,14 +80,6 @@ abstract class Command implements CommandInterface
return $data;
}
/**
* {@inheritdoc}
*/
public function parseResp3Response($data)
{
return $data;
}
/**
* Normalizes the arguments array passed to a Redis command.
*
@@ -134,67 +123,4 @@ abstract class Command implements CommandInterface
return $argument !== false && $argument !== null;
});
}
/**
* {@inheritDoc}
*/
public function serializeCommand(): string
{
$commandID = $this->getId();
$arguments = $this->getArguments();
$cmdlen = strlen($commandID);
$reqlen = count($arguments) + 1;
$buffer = "*{$reqlen}\r\n\${$cmdlen}\r\n{$commandID}\r\n";
foreach ($arguments as $argument) {
$arglen = strlen(strval($argument));
$buffer .= "\${$arglen}\r\n{$argument}\r\n";
}
return $buffer;
}
/**
* {@inheritDoc}
*/
public static function deserializeCommand(string $serializedCommand): CommandInterface
{
if ($serializedCommand[0] !== '*') {
throw new UnexpectedValueException('Invalid serializing format');
}
$commandArray = explode("\r\n", $serializedCommand);
$commandId = $commandArray[2];
$classPath = __NAMESPACE__ . '\Redis\\';
// Check if given command is a module command.
if (count($commandIdArray = explode('.', $commandId)) > 1) {
// Fetch module configuration to resolve namespace.
$moduleConfiguration = array_filter(
ClientConfiguration::getModules(),
static function ($module) use ($commandIdArray) {
return $module['commandPrefix'] === $commandIdArray[0];
}
);
$commandClass = strtoupper($commandIdArray[0] . $commandIdArray[1]);
$classPath .= array_shift($moduleConfiguration)['name'] . '\\' . $commandClass;
} else {
$classPath .= $commandIdArray[0];
}
$command = new $classPath();
$arguments = [];
for ($i = 4, $iMax = count($commandArray); $i < $iMax; $i++) {
$arguments[] = $commandArray[$i];
++$i;
}
$command->setArguments($arguments);
return $command;
}
}
-23
View File
@@ -77,27 +77,4 @@ interface CommandInterface
* @return mixed
*/
public function parseResponse($data);
/**
* Parses RESP3 protocol response and returns a PHP object.
*
* @param mixed $data
* @return mixed
*/
public function parseResp3Response($data);
/**
* Returns RESP-formatted representation of command.
*
* @return string
*/
public function serializeCommand(): string;
/**
* Creates command object from given serialized representation.
*
* @param string $serializedCommand
* @return static
*/
public static function deserializeCommand(string $serializedCommand): CommandInterface;
}
-32
View File
@@ -1,32 +0,0 @@
<?php
/*
* This file is part of the Predis package.
*
* (c) 2009-2020 Daniele Alessandri
* (c) 2021-2025 Till Krüss
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Predis\Command\Container;
use Predis\Response\Status;
/**
* @method string getName()
* @method Status kill(...$arguments)
* @method string list(string $type = null, int ...$clientId)
* @method Status noEvict(bool $enable = null)
* @method Status noTouch(bool $enable = null)
* @method Status setInfo(string $modifier = null, string $value = null)
* @method Status setName(string $connectionName)
*/
class CLIENT extends AbstractContainer
{
public function getContainerCommandId(): string
{
return 'CLIENT';
}
}
-30
View File
@@ -1,30 +0,0 @@
<?php
/*
* This file is part of the Predis package.
*
* (c) 2009-2020 Daniele Alessandri
* (c) 2021-2025 Till Krüss
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Predis\Command\Container;
use Predis\Response\Status;
/**
* @method Status create(string $key, string $group, string $id, bool $mkStream = false, ?string $entriesRead = null)
* @method int createConsumer(string $key, string $group, string $consumer)
* @method int delConsumer(string $key, string $group, string $consumer)
* @method int destroy(string $key, string $group)
* @method Status setId(string $key, string $group, string $id, ?string $entriesRead = null)
*/
class XGROUP extends AbstractContainer
{
public function getContainerCommandId(): string
{
return 'xgroup';
}
}
-28
View File
@@ -1,28 +0,0 @@
<?php
/*
* This file is part of the Predis package.
*
* (c) 2009-2020 Daniele Alessandri
* (c) 2021-2025 Till Krüss
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Predis\Command\Container;
use Predis\Command\Argument\Stream\XInfoStreamOptions;
/**
* @method array consumers(string $key, string $group)
* @method array groups(string $key)
* @method array stream(string $key, XInfoStreamOptions $options = null)
*/
class XINFO extends AbstractContainer
{
public function getContainerCommandId(): string
{
return 'XINFO';
}
}
-111
View File
@@ -1,111 +0,0 @@
<?php
/*
* This file is part of the Predis package.
*
* (c) 2009-2020 Daniele Alessandri
* (c) 2021-2025 Till Krüss
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Predis\Command;
abstract class PrefixableCommand extends Command implements PrefixableCommandInterface
{
/**
* {@inheritDoc}
*/
abstract public function getId();
/**
* {@inheritDoc}
*/
abstract public function prefixKeys($prefix);
/**
* Applies prefix for all arguments.
*
* @param string $prefix
* @return void
*/
public function applyPrefixForAllArguments(string $prefix): void
{
$this->setRawArguments(
array_map(static function ($key) use ($prefix) {
return $prefix . $key;
}, $this->getArguments())
);
}
/**
* Applies prefix for first argument.
*
* @param string $prefix
* @return void
*/
public function applyPrefixForFirstArgument(string $prefix): void
{
$arguments = $this->getArguments();
$arguments[0] = $prefix . $arguments[0];
$this->setRawArguments($arguments);
}
/**
* Applies prefix for interleaved arguments.
*
* @param string $prefix
* @return void
*/
public function applyPrefixForInterleavedArgument(string $prefix): void
{
if ($arguments = $this->getArguments()) {
$length = count($arguments);
for ($i = 0; $i < $length; $i += 2) {
$arguments[$i] = "$prefix{$arguments[$i]}";
}
$this->setRawArguments($arguments);
}
}
/**
* Applies prefix for all keys except last one.
*
* @param string $prefix
* @return void
*/
public function applyPrefixSkippingLastArgument(string $prefix): void
{
if ($arguments = $this->getArguments()) {
$length = count($arguments);
for ($i = 0; $i < $length - 1; ++$i) {
$arguments[$i] = "$prefix{$arguments[$i]}";
}
$this->setRawArguments($arguments);
}
}
/**
* Applies prefix for all keys except first one.
*
* @param string $prefix
* @return void
*/
public function applyPrefixSkippingFirstArgument(string $prefix): void
{
if ($arguments = $this->getArguments()) {
$length = count($arguments);
for ($i = 1; $i < $length; ++$i) {
$arguments[$i] = "$prefix{$arguments[$i]}";
}
$this->setRawArguments($arguments);
}
}
}
@@ -31,6 +31,284 @@ class KeyPrefixProcessor implements ProcessorInterface
public function __construct($prefix)
{
$this->prefix = $prefix;
$prefixFirst = static::class . '::first';
$prefixFirstTwo = static::class . '::firstTwo';
$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' => $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,
'SMISMEMBER' => $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' => $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' => $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' => $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' => $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' => $prefixFirst,
'BITFIELD' => $prefixFirst,
'GEOADD' => $prefixFirst,
'GEOHASH' => $prefixFirst,
'GEOPOS' => $prefixFirst,
'GEODIST' => $prefixFirst,
'GEORADIUS' => $prefixGeoradius,
'GEORADIUSBYMEMBER' => $prefixGeoradius,
/* ---------------- Redis 5.0 ---------------- */
'XADD' => $prefixFirst,
'XRANGE' => $prefixFirst,
'XREVRANGE' => $prefixFirst,
'XDEL' => $prefixFirst,
'XLEN' => $prefixFirst,
'XACK' => $prefixFirst,
'XTRIM' => $prefixFirst,
'ZPOPMIN' => $prefixFirst,
'ZPOPMAX' => $prefixFirst,
/* ---------------- Redis 6.2 ---------------- */
'GETDEL' => $prefixFirst,
'ZMSCORE' => $prefixFirst,
'LMOVE' => $prefixFirstTwo,
'BLMOVE' => $prefixFirstTwo,
'GEOSEARCH' => $prefixFirst,
/* ---------------- Redis 7.0 ---------------- */
'EXPIRETIME' => $prefixFirst,
/* RedisJSON */
'JSON.ARRAPPEND' => $prefixFirst,
'JSON.ARRINDEX' => $prefixFirst,
'JSON.ARRINSERT' => $prefixFirst,
'JSON.ARRLEN' => $prefixFirst,
'JSON.ARRPOP' => $prefixFirst,
'JSON.ARRTRIM' => $prefixFirst,
'JSON.CLEAR' => $prefixFirst,
'JSON.DEBUG MEMORY' => $prefixFirst,
'JSON.DEL' => $prefixFirst,
'JSON.FORGET' => $prefixFirst,
'JSON.GET' => $prefixFirst,
'JSON.MGET' => $prefixAll,
'JSON.NUMINCRBY' => $prefixFirst,
'JSON.OBJKEYS' => $prefixFirst,
'JSON.OBJLEN' => $prefixFirst,
'JSON.RESP' => $prefixFirst,
'JSON.SET' => $prefixFirst,
'JSON.STRAPPEND' => $prefixFirst,
'JSON.STRLEN' => $prefixFirst,
'JSON.TOGGLE' => $prefixFirst,
'JSON.TYPE' => $prefixFirst,
/* RedisBloom */
'BF.ADD' => $prefixFirst,
'BF.EXISTS' => $prefixFirst,
'BF.INFO' => $prefixFirst,
'BF.INSERT' => $prefixFirst,
'BF.LOADCHUNK' => $prefixFirst,
'BF.MADD' => $prefixFirst,
'BF.MEXISTS' => $prefixFirst,
'BF.RESERVE' => $prefixFirst,
'BF.SCANDUMP' => $prefixFirst,
'CF.ADD' => $prefixFirst,
'CF.ADDNX' => $prefixFirst,
'CF.COUNT' => $prefixFirst,
'CF.DEL' => $prefixFirst,
'CF.EXISTS' => $prefixFirst,
'CF.INFO' => $prefixFirst,
'CF.INSERT' => $prefixFirst,
'CF.INSERTNX' => $prefixFirst,
'CF.LOADCHUNK' => $prefixFirst,
'CF.MEXISTS' => $prefixFirst,
'CF.RESERVE' => $prefixFirst,
'CF.SCANDUMP' => $prefixFirst,
'CMS.INCRBY' => $prefixFirst,
'CMS.INFO' => $prefixFirst,
'CMS.INITBYDIM' => $prefixFirst,
'CMS.INITBYPROB' => $prefixFirst,
'CMS.QUERY' => $prefixFirst,
'TDIGEST.ADD' => $prefixFirst,
'TDIGEST.BYRANK' => $prefixFirst,
'TDIGEST.BYREVRANK' => $prefixFirst,
'TDIGEST.CDF' => $prefixFirst,
'TDIGEST.CREATE' => $prefixFirst,
'TDIGEST.INFO' => $prefixFirst,
'TDIGEST.MAX' => $prefixFirst,
'TDIGEST.MIN' => $prefixFirst,
'TDIGEST.QUANTILE' => $prefixFirst,
'TDIGEST.RANK' => $prefixFirst,
'TDIGEST.RESET' => $prefixFirst,
'TDIGEST.REVRANK' => $prefixFirst,
'TDIGEST.TRIMMED_MEAN' => $prefixFirst,
'TOPK.ADD' => $prefixFirst,
'TOPK.INCRBY' => $prefixFirst,
'TOPK.INFO' => $prefixFirst,
'TOPK.LIST' => $prefixFirst,
'TOPK.QUERY' => $prefixFirst,
'TOPK.RESERVE' => $prefixFirst,
/* RediSearch */
'FT.AGGREGATE' => $prefixFirst,
'FT.ALTER' => $prefixFirst,
'FT.CREATE' => $prefixFirst,
'FT.CURSOR DEL' => $prefixFirst,
'FT.CURSOR READ' => $prefixFirst,
'FT.DROPINDEX' => $prefixFirst,
'FT.EXPLAIN' => $prefixFirst,
'FT.INFO' => $prefixFirst,
'FT.PROFILE' => $prefixFirst,
'FT.SEARCH' => $prefixFirst,
'FT.SPELLCHECK' => $prefixFirst,
'FT.SYNDUMP' => $prefixFirst,
'FT.SYNUPDATE' => $prefixFirst,
'FT.TAGVALS' => $prefixFirst,
/* Redis TimeSeries */
'TS.ADD' => $prefixFirst,
'TS.ALTER' => $prefixFirst,
'TS.CREATE' => $prefixFirst,
'TS.DECRBY' => $prefixFirst,
'TS.DEL' => $prefixFirst,
'TS.GET' => $prefixFirst,
'TS.INCRBY' => $prefixFirst,
'TS.INFO' => $prefixFirst,
'TS.MGET' => $prefixFirst,
'TS.MRANGE' => $prefixFirst,
'TS.MREVRANGE' => $prefixFirst,
'TS.QUERYINDEX' => $prefixFirst,
'TS.RANGE' => $prefixFirst,
'TS.REVRANGE' => $prefixFirst,
];
}
/**
@@ -107,4 +385,225 @@ class KeyPrefixProcessor implements ProcessorInterface
{
return $this->getPrefix();
}
/**
* Applies the specified prefix only the first argument.
*
* @param CommandInterface $command Command instance.
* @param string $prefix Prefix string.
*/
public static function first(CommandInterface $command, $prefix)
{
if ($arguments = $command->getArguments()) {
$arguments[0] = "$prefix{$arguments[0]}";
$command->setRawArguments($arguments);
}
}
/**
* Applies the specified prefix only to the first two arguments.
*
* @param CommandInterface $command Command instance.
* @param string $prefix Prefix string.
*/
public static function firstTwo(CommandInterface $command, $prefix)
{
$arguments = $command->getArguments();
$length = min(count($arguments), 2);
for ($i = 0; $i < $length; $i++) {
$arguments[$i] = "$prefix{$arguments[$i]}";
}
$command->setRawArguments($arguments);
}
/**
* Applies the specified prefix to all the arguments.
*
* @param CommandInterface $command Command instance.
* @param string $prefix Prefix string.
*/
public static function all(CommandInterface $command, $prefix)
{
if ($arguments = $command->getArguments()) {
foreach ($arguments as &$key) {
$key = "$prefix$key";
}
$command->setRawArguments($arguments);
}
}
/**
* Applies the specified prefix only to even arguments in the list.
*
* @param CommandInterface $command Command instance.
* @param string $prefix Prefix string.
*/
public static function interleaved(CommandInterface $command, $prefix)
{
if ($arguments = $command->getArguments()) {
$length = count($arguments);
for ($i = 0; $i < $length; $i += 2) {
$arguments[$i] = "$prefix{$arguments[$i]}";
}
$command->setRawArguments($arguments);
}
}
/**
* Applies the specified prefix to all the arguments but the first one.
*
* @param CommandInterface $command Command instance.
* @param string $prefix Prefix string.
*/
public static function skipFirst(CommandInterface $command, $prefix)
{
if ($arguments = $command->getArguments()) {
$length = count($arguments);
for ($i = 1; $i < $length; ++$i) {
$arguments[$i] = "$prefix{$arguments[$i]}";
}
$command->setRawArguments($arguments);
}
}
/**
* Applies the specified prefix to all the arguments but the last one.
*
* @param CommandInterface $command Command instance.
* @param string $prefix Prefix string.
*/
public static function skipLast(CommandInterface $command, $prefix)
{
if ($arguments = $command->getArguments()) {
$length = count($arguments);
for ($i = 0; $i < $length - 1; ++$i) {
$arguments[$i] = "$prefix{$arguments[$i]}";
}
$command->setRawArguments($arguments);
}
}
/**
* Applies the specified prefix to the keys of a SORT command.
*
* @param CommandInterface $command Command instance.
* @param string $prefix Prefix string.
*/
public static function sort(CommandInterface $command, $prefix)
{
if ($arguments = $command->getArguments()) {
$arguments[0] = "$prefix{$arguments[0]}";
if (($count = count($arguments)) > 1) {
for ($i = 1; $i < $count; ++$i) {
switch (strtoupper($arguments[$i])) {
case 'BY':
case 'STORE':
$arguments[$i] = "$prefix{$arguments[++$i]}";
break;
case 'GET':
$value = $arguments[++$i];
if ($value !== '#') {
$arguments[$i] = "$prefix$value";
}
break;
case 'LIMIT':
$i += 2;
break;
}
}
}
$command->setRawArguments($arguments);
}
}
/**
* Applies the specified prefix to the keys of an EVAL-based command.
*
* @param CommandInterface $command Command instance.
* @param string $prefix Prefix string.
*/
public static function evalKeys(CommandInterface $command, $prefix)
{
if ($arguments = $command->getArguments()) {
for ($i = 2; $i < $arguments[1] + 2; ++$i) {
$arguments[$i] = "$prefix{$arguments[$i]}";
}
$command->setRawArguments($arguments);
}
}
/**
* Applies the specified prefix to the keys of Z[INTERSECTION|UNION]STORE.
*
* @param CommandInterface $command Command instance.
* @param string $prefix Prefix string.
*/
public static function zsetStore(CommandInterface $command, $prefix)
{
if ($arguments = $command->getArguments()) {
$arguments[0] = "$prefix{$arguments[0]}";
$length = ((int) $arguments[1]) + 2;
for ($i = 2; $i < $length; ++$i) {
$arguments[$i] = "$prefix{$arguments[$i]}";
}
$command->setRawArguments($arguments);
}
}
/**
* Applies the specified prefix to the key of a MIGRATE command.
*
* @param CommandInterface $command Command instance.
* @param string $prefix Prefix string.
*/
public static function migrate(CommandInterface $command, $prefix)
{
if ($arguments = $command->getArguments()) {
$arguments[2] = "$prefix{$arguments[2]}";
$command->setRawArguments($arguments);
}
}
/**
* Applies the specified prefix to the key of a GEORADIUS command.
*
* @param CommandInterface $command Command instance.
* @param string $prefix Prefix string.
*/
public static function georadius(CommandInterface $command, $prefix)
{
if ($arguments = $command->getArguments()) {
$arguments[0] = "$prefix{$arguments[0]}";
$startIndex = $command->getId() === 'GEORADIUS' ? 5 : 4;
if (($count = count($arguments)) > $startIndex) {
for ($i = $startIndex; $i < $count; ++$i) {
switch (strtoupper($arguments[$i])) {
case 'STORE':
case 'STOREDIST':
$arguments[$i] = "$prefix{$arguments[++$i]}";
break;
}
}
}
$command->setRawArguments($arguments);
}
}
}
-71
View File
@@ -12,9 +12,6 @@
namespace Predis\Command;
use Predis\ClientConfiguration;
use UnexpectedValueException;
/**
* Class representing a generic Redis command.
*
@@ -123,72 +120,4 @@ final class RawCommand implements CommandInterface
{
return $data;
}
/**
* {@inheritdoc}
*/
public function parseResp3Response($data)
{
return $data;
}
/**
* {@inheritDoc}
*/
public function serializeCommand(): string
{
$commandID = $this->getId();
$arguments = $this->getArguments();
$cmdlen = strlen($commandID);
$reqlen = count($arguments) + 1;
$buffer = "*{$reqlen}\r\n\${$cmdlen}\r\n{$commandID}\r\n";
foreach ($arguments as $argument) {
$arglen = strlen(strval($argument));
$buffer .= "\${$arglen}\r\n{$argument}\r\n";
}
return $buffer;
}
public static function deserializeCommand(string $serializedCommand): CommandInterface
{
if ($serializedCommand[0] !== '*') {
throw new UnexpectedValueException('Invalid serializing format');
}
$commandArray = explode("\r\n", $serializedCommand);
$commandId = $commandArray[2];
$classPath = __NAMESPACE__ . '\Redis\\';
// Check if given command is a module command.
if (count($commandIdArray = explode('.', $commandId)) > 1) {
// Fetch module configuration to resolve namespace.
$moduleConfiguration = array_filter(
ClientConfiguration::getModules(),
static function ($module) use ($commandIdArray) {
return $module['commandPrefix'] === $commandIdArray[0];
}
);
$commandClass = strtoupper($commandIdArray[0] . $commandIdArray[1]);
$classPath .= array_shift($moduleConfiguration)['name'] . '\\' . $commandClass;
} else {
$classPath .= $commandIdArray[0];
}
$command = new $classPath();
$arguments = [];
for ($i = 4, $iMax = count($commandArray); $i < $iMax; $i++) {
$arguments[] = $commandArray[$i];
++$i;
}
$command->setArguments($arguments);
return $command;
}
}
+1 -6
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see http://redis.io/commands/append
@@ -26,9 +26,4 @@ class APPEND extends RedisCommand
{
return 'APPEND';
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
@@ -40,13 +40,4 @@ abstract class BZPOPBase extends RedisCommand
return array_combine([$key], [[$data[0] => $data[1]]]);
}
/**
* @param $data
* @return array|false|mixed|null[]|string|null
*/
public function parseResp3Response($data)
{
return $this->parseResponse($data);
}
}
+1 -6
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\BitByte;
/**
@@ -31,9 +31,4 @@ class BITCOUNT extends RedisCommand
{
return 'BITCOUNT';
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
+1 -6
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see http://redis.io/commands/bitfield
@@ -26,9 +26,4 @@ class BITFIELD extends RedisCommand
{
return 'BITFIELD';
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
+1 -16
View File
@@ -12,16 +12,13 @@
namespace Predis\Command\Redis;
use InvalidArgumentException;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see http://redis.io/commands/bitop
*/
class BITOP extends RedisCommand
{
private const VALID_OPERATIONS = ['AND', 'OR', 'XOR', 'NOT', 'DIFF', 'DIFF1', 'ANDOR', 'ONE'];
/**
* {@inheritdoc}
*/
@@ -41,18 +38,6 @@ class BITOP extends RedisCommand
array_unshift($arguments, $operation, $destination);
}
if (!empty($arguments)) {
$operation = strtoupper($arguments[0]);
if (!in_array($operation, self::VALID_OPERATIONS, false)) {
throw new InvalidArgumentException('BITOP operation must be one of: AND, OR, XOR, NOT, DIFF, DIFF1, ANDOR, ONE');
}
}
parent::setArguments($arguments);
}
public function prefixKeys($prefix)
{
$this->applyPrefixSkippingFirstArgument($prefix);
}
}
+1 -6
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\BitByte;
/**
@@ -31,9 +31,4 @@ class BITPOS extends RedisCommand
{
return 'BITPOS';
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
+1 -6
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see http://redis.io/commands/blpop
@@ -39,9 +39,4 @@ class BLPOP extends RedisCommand
parent::setArguments($arguments);
}
public function prefixKeys($prefix)
{
$this->applyPrefixSkippingLastArgument($prefix);
}
}
+1 -6
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see http://redis.io/commands/brpop
@@ -39,9 +39,4 @@ class BRPOP extends RedisCommand
parent::setArguments($arguments);
}
public function prefixKeys($prefix)
{
$this->applyPrefixSkippingLastArgument($prefix);
}
}
+1 -6
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see http://redis.io/commands/brpoplpush
@@ -26,9 +26,4 @@ class BRPOPLPUSH extends RedisCommand
{
return 'BRPOPLPUSH';
}
public function prefixKeys($prefix)
{
$this->applyPrefixSkippingLastArgument($prefix);
}
}
+1 -6
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis\BloomFilter;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see https://redis.io/commands/bf.add/
@@ -26,9 +26,4 @@ class BFADD extends RedisCommand
{
return 'BF.ADD';
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
+1 -6
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis\BloomFilter;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see https://redis.io/commands/bf.exists/
@@ -25,9 +25,4 @@ class BFEXISTS extends RedisCommand
{
return 'BF.EXISTS';
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
+1 -6
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis\BloomFilter;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
use UnexpectedValueException;
/**
@@ -76,9 +76,4 @@ class BFINFO extends RedisCommand
return $data;
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
+1 -6
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis\BloomFilter;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\BloomFilters\Capacity;
use Predis\Command\Traits\BloomFilters\Error;
use Predis\Command\Traits\BloomFilters\Expansion;
@@ -48,11 +48,6 @@ class BFINSERT extends RedisCommand
return 'BF.INSERT';
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
public function setArguments(array $arguments)
{
$this->setNoCreate($arguments);
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis\BloomFilter;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see https://redis.io/commands/bf.loadchunk/
@@ -25,9 +25,4 @@ class BFLOADCHUNK extends RedisCommand
{
return 'BF.LOADCHUNK';
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
+1 -6
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis\BloomFilter;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see https://redis.io/commands/bf.madd/
@@ -26,9 +26,4 @@ class BFMADD extends RedisCommand
{
return 'BF.MADD';
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
+1 -6
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis\BloomFilter;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see https://redis.io/commands/bf.mexists/
@@ -25,9 +25,4 @@ class BFMEXISTS extends RedisCommand
{
return 'BF.MEXISTS';
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
+1 -6
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis\BloomFilter;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\BloomFilters\Expansion;
/**
@@ -46,9 +46,4 @@ class BFRESERVE extends RedisCommand
$this->setExpansion($arguments);
$this->filterArguments();
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
+1 -6
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis\BloomFilter;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see https://redis.io/commands/bf.scandump/
@@ -26,9 +26,4 @@ class BFSCANDUMP extends RedisCommand
{
return 'BF.SCANDUMP';
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
-80
View File
@@ -30,77 +30,6 @@ class CLIENT extends RedisCommand
return 'CLIENT';
}
public function setArguments(array $arguments)
{
switch ($arguments[0]) {
case 'LIST':
$this->setListArguments($arguments);
break;
case 'NOEVICT':
$arguments[0] = 'NO-EVICT';
$this->setNoTouchArguments($arguments);
break;
case 'NOTOUCH':
$arguments[0] = 'NO-TOUCH';
$this->setNoTouchArguments($arguments);
break;
case 'SETINFO':
$this->setSetInfoArguments($arguments);
break;
default:
parent::setArguments($arguments);
}
}
private function setListArguments(array $arguments): void
{
$processedArguments = [$arguments[0]];
if (array_key_exists(1, $arguments) && null !== $arguments[1]) {
array_push($processedArguments, 'TYPE', strtoupper($arguments[1]));
}
if (array_key_exists(2, $arguments)) {
array_push($processedArguments, 'ID', $arguments[2]);
}
if (count($arguments) > 3) {
for ($i = 3, $iMax = count($arguments); $i < $iMax; $i++) {
$processedArguments[] = $arguments[$i];
}
}
parent::setArguments($processedArguments);
}
private function setNoTouchArguments(array $arguments): void
{
$processedArguments = [$arguments[0]];
if (array_key_exists(1, $arguments) && null !== $arguments[1]) {
$modifier = ($arguments[1]) ? 'ON' : 'OFF';
$processedArguments[] = $modifier;
}
parent::setArguments($processedArguments);
}
private function setSetInfoArguments(array $arguments): void
{
$processedArguments = [$arguments[0]];
if (
array_key_exists(1, $arguments)
&& null !== $arguments[1]
&& array_key_exists(2, $arguments)
&& null !== $arguments[2]
) {
array_push($processedArguments, strtoupper($arguments[1]), $arguments[2]);
}
parent::setArguments($processedArguments);
}
/**
* {@inheritdoc}
*/
@@ -143,13 +72,4 @@ class CLIENT extends RedisCommand
return $clients;
}
/**
* @param $data
* @return array|mixed|string|null
*/
public function parseResp3Response($data)
{
return $this->parseResponse($data);
}
}
@@ -10,17 +10,15 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Container;
namespace Predis\Command\Redis\Container;
use Predis\Response\Status;
/**
* @method array cat(string $category = null)
* @method Status dryRun(string $username, string $command, ...$arguments)
* @method int delUser(string ...$username)
* @method array getUser(string $username)
* @method Status setUser(string $username, string ...$rules)
* @method string whoami()
*/
class ACL extends AbstractContainer
{
@@ -10,7 +10,7 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Container;
namespace Predis\Command\Redis\Container;
use Predis\ClientInterface;
@@ -10,7 +10,7 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Container;
namespace Predis\Command\Redis\Container;
use Predis\Response\Status;
@@ -10,7 +10,7 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Container;
namespace Predis\Command\Redis\Container;
use Predis\ClientConfiguration;
use Predis\ClientInterface;
@@ -18,7 +18,7 @@ use UnexpectedValueException;
class ContainerFactory
{
private const CONTAINER_NAMESPACE = "Predis\Command\Container";
private const CONTAINER_NAMESPACE = "Predis\Command\Redis\Container";
/**
* Mappings for class names that corresponds to PHP reserved words.
@@ -26,7 +26,7 @@ class ContainerFactory
* @var array
*/
private static $specialMappings = [
'FUNCTION' => FUNCTIONS::class,
'FUNCTION' => FunctionContainer::class,
];
/**
@@ -10,7 +10,7 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Container;
namespace Predis\Command\Redis\Container;
interface ContainerInterface
{
@@ -10,7 +10,7 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Container;
namespace Predis\Command\Redis\Container;
use Predis\Response\Status;
@@ -19,12 +19,12 @@ use Predis\Response\Status;
* @method string dump()
* @method Status flush(?string $mode = null)
* @method Status kill()
* @method array list(string $libraryNamePattern = null, bool $withCode = false)
* @method array list(?string $libraryNamePattern = null, bool $withCode = false)
* @method string load(string $functionCode, bool $replace = 'false')
* @method Status restore(string $value, string $policy = null)
* @method Status restore(string $value, ?string $policy = null)
* @method array stats()
*/
class FUNCTIONS extends AbstractContainer
class FunctionContainer extends AbstractContainer
{
public function getContainerCommandId(): string
{
@@ -10,9 +10,9 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Container\Json;
namespace Predis\Command\Redis\Container\Json;
use Predis\Command\Container\AbstractContainer;
use Predis\Command\Redis\Container\AbstractContainer;
/**
* @method array memory(string $key, string $path)
@@ -10,9 +10,9 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Container\Search;
namespace Predis\Command\Redis\Container\Search;
use Predis\Command\Container\AbstractContainer;
use Predis\Command\Redis\Container\AbstractContainer;
use Predis\Response\Status;
/**
@@ -10,10 +10,10 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Container\Search;
namespace Predis\Command\Redis\Container\Search;
use Predis\Command\Argument\Search\CursorArguments;
use Predis\Command\Container\AbstractContainer;
use Predis\Command\Redis\Container\AbstractContainer;
use Predis\Response\Status;
/**
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis\CountMinSketch;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see https://redis.io/commands/cms.incrby/
@@ -26,9 +26,4 @@ class CMSINCRBY extends RedisCommand
{
return 'CMS.INCRBY';
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
+1 -6
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis\CountMinSketch;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see https://redis.io/commands/cms.info/
@@ -42,9 +42,4 @@ class CMSINFO extends RedisCommand
return $data;
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis\CountMinSketch;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see https://redis.io/commands/cms.initbydim/
@@ -25,9 +25,4 @@ class CMSINITBYDIM extends RedisCommand
{
return 'CMS.INITBYDIM';
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis\CountMinSketch;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see https://redis.io/commands/cms.initbyprob/
@@ -25,9 +25,4 @@ class CMSINITBYPROB extends RedisCommand
{
return 'CMS.INITBYPROB';
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
+1 -14
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis\CountMinSketch;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see https://redis.io/commands/cms.merge/
@@ -39,17 +39,4 @@ class CMSMERGE extends RedisCommand
parent::setArguments($processedArguments);
}
public function prefixKeys($prefix)
{
if ($arguments = $this->getArguments()) {
$arguments[0] = $prefix . $arguments[0];
for ($i = 2, $iMax = (int) $arguments[1] + 2; $i < $iMax; $i++) {
$arguments[$i] = $prefix . $arguments[$i];
}
$this->setRawArguments($arguments);
}
}
}
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis\CountMinSketch;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see https://redis.io/commands/cms.query/
@@ -25,9 +25,4 @@ class CMSQUERY extends RedisCommand
{
return 'CMS.QUERY';
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
+1 -6
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis\CuckooFilter;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see https://redis.io/commands/cf.add/
@@ -25,9 +25,4 @@ class CFADD extends RedisCommand
{
return 'CF.ADD';
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
+1 -6
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis\CuckooFilter;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see https://redis.io/commands/cf.addnx/
@@ -25,9 +25,4 @@ class CFADDNX extends RedisCommand
{
return 'CF.ADDNX';
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
+1 -6
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis\CuckooFilter;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see https://redis.io/commands/cf.count/
@@ -26,9 +26,4 @@ class CFCOUNT extends RedisCommand
{
return 'CF.COUNT';
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
+1 -6
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis\CuckooFilter;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see https://redis.io/commands/cf.del/
@@ -27,9 +27,4 @@ class CFDEL extends RedisCommand
{
return 'CF.DEL';
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
+1 -6
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis\CuckooFilter;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see https://redis.io/commands/cf.exists/
@@ -25,9 +25,4 @@ class CFEXISTS extends RedisCommand
{
return 'CF.EXISTS';
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
+1 -6
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis\CuckooFilter;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see https://redis.io/commands/cf.info/
@@ -42,9 +42,4 @@ class CFINFO extends RedisCommand
return $data;
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
+1 -6
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis\CuckooFilter;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\BloomFilters\Capacity;
use Predis\Command\Traits\BloomFilters\Items;
use Predis\Command\Traits\BloomFilters\NoCreate;
@@ -49,9 +49,4 @@ class CFINSERT extends RedisCommand
$this->setCapacity($arguments);
$this->filterArguments();
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis\CuckooFilter;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see https://redis.io/commands/cf.loadchunk/
@@ -26,9 +26,4 @@ class CFLOADCHUNK extends RedisCommand
{
return 'CF.LOADCHUNK';
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
+1 -6
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis\CuckooFilter;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see https://redis.io/commands/cf.mexists/
@@ -25,9 +25,4 @@ class CFMEXISTS extends RedisCommand
{
return 'CF.MEXISTS';
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
+1 -6
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis\CuckooFilter;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\BloomFilters\BucketSize;
use Predis\Command\Traits\BloomFilters\Expansion;
use Predis\Command\Traits\BloomFilters\MaxIterations;
@@ -49,9 +49,4 @@ class CFRESERVE extends RedisCommand
$this->setBucketSize($arguments);
$this->filterArguments();
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis\CuckooFilter;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see https://redis.io/commands/cf.scandump/
@@ -26,9 +26,4 @@ class CFSCANDUMP extends RedisCommand
{
return 'CF.SCANDUMP';
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
+1 -6
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see http://redis.io/commands/decr
@@ -26,9 +26,4 @@ class DECR extends RedisCommand
{
return 'DECR';
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
+1 -6
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see http://redis.io/commands/decrby
@@ -26,9 +26,4 @@ class DECRBY extends RedisCommand
{
return 'DECRBY';
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
+1 -6
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see http://redis.io/commands/del
@@ -36,9 +36,4 @@ class DEL extends RedisCommand
parent::setArguments($arguments);
}
public function prefixKeys($prefix)
{
$this->applyPrefixForAllArguments($prefix);
}
}
+1 -6
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see http://redis.io/commands/dump
@@ -26,9 +26,4 @@ class DUMP extends RedisCommand
{
return 'DUMP';
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
+1 -12
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see http://redis.io/commands/eval
@@ -36,15 +36,4 @@ class EVAL_ extends RedisCommand
{
return sha1($this->getArgument(0));
}
public function prefixKeys($prefix)
{
if ($arguments = $this->getArguments()) {
for ($i = 2; $i < $arguments[1] + 2; ++$i) {
$arguments[$i] = "$prefix{$arguments[$i]}";
}
$this->setRawArguments($arguments);
}
}
}
+1 -6
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see http://redis.io/commands/exists
@@ -26,9 +26,4 @@ class EXISTS extends RedisCommand
{
return 'EXISTS';
}
public function prefixKeys($prefix)
{
$this->applyPrefixForAllArguments($prefix);
}
}
+1 -6
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\Expire\ExpireOptions;
/**
@@ -33,9 +33,4 @@ class EXPIRE extends RedisCommand
{
return 'EXPIRE';
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
+1 -6
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\Expire\ExpireOptions;
/**
@@ -32,9 +32,4 @@ class EXPIREAT extends RedisCommand
{
return 'EXPIREAT';
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
+1 -6
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see https://redis.io/commands/expiretime/
@@ -26,9 +26,4 @@ class EXPIRETIME extends RedisCommand
{
return 'EXPIRETIME';
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
+1 -16
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\Keys;
/**
@@ -30,19 +30,4 @@ class FCALL extends RedisCommand
{
return 'FCALL';
}
public function prefixKeys($prefix)
{
$arguments = $this->getArguments();
if (isset($arguments[1])) {
$numkeys = $arguments[1];
for ($i = 2; $i < $numkeys + 2; $i++) {
$arguments[$i] = $prefix . $arguments[$i];
}
}
$this->setRawArguments($arguments);
}
}
+15 -95
View File
@@ -13,6 +13,8 @@
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
use Predis\Command\Strategy\StrategyResolverInterface;
use Predis\Command\Strategy\SubcommandStrategyResolver;
/**
* @see https://redis.io/commands/?name=function
@@ -22,6 +24,16 @@ use Predis\Command\Command as RedisCommand;
*/
class FUNCTIONS extends RedisCommand
{
/**
* @var StrategyResolverInterface
*/
private $strategyResolver;
public function __construct()
{
$this->strategyResolver = new SubcommandStrategyResolver();
}
public function getId()
{
return 'FUNCTION';
@@ -29,102 +41,10 @@ class FUNCTIONS extends RedisCommand
public function setArguments(array $arguments)
{
switch ($arguments[0]) {
case 'FLUSH':
$this->setFlushArguments($arguments);
break;
case 'LIST':
$this->setListArguments($arguments);
break;
case 'LOAD':
$this->setLoadArguments($arguments);
break;
case 'RESTORE':
$this->setRestoreArguments($arguments);
break;
default:
parent::setArguments($arguments);
}
$strategy = $this->strategyResolver->resolve('functions', strtolower($arguments[0]));
$arguments = $strategy->processArguments($arguments);
parent::setArguments($arguments);
$this->filterArguments();
}
/**
* @param array $arguments
* @return void
*/
private function setFlushArguments(array $arguments): void
{
$processedArguments = [$arguments[0]];
if (array_key_exists(1, $arguments) && null !== $arguments[1]) {
$processedArguments[] = strtoupper($arguments[1]);
}
parent::setArguments($processedArguments);
}
/**
* @param array $arguments
* @return void
*/
private function setListArguments(array $arguments): void
{
$processedArguments = [$arguments[0]];
if (array_key_exists(1, $arguments) && null !== $arguments[1]) {
array_push($processedArguments, 'LIBRARYNAME', $arguments[1]);
}
if (array_key_exists(2, $arguments) && true === $arguments[2]) {
$processedArguments[] = 'WITHCODE';
}
parent::setArguments($processedArguments);
}
/**
* @param array $arguments
* @return void
*/
private function setLoadArguments(array $arguments): void
{
if (count($arguments) <= 2) {
parent::setArguments($arguments);
return;
}
$processedArguments = [$arguments[0]];
$replace = array_pop($arguments);
if (is_bool($replace) && $replace) {
$processedArguments[] = 'REPLACE';
} elseif (!is_bool($replace)) {
$processedArguments[] = $replace;
}
$processedArguments[] = $arguments[1];
parent::setArguments($processedArguments);
}
/**
* @param array $arguments
* @return void
*/
private function setRestoreArguments(array $arguments): void
{
$processedArguments = [$arguments[0], $arguments[1]];
if (array_key_exists(2, $arguments) && null !== $arguments[2]) {
$processedArguments[] = strtoupper($arguments[2]);
}
parent::setArguments($processedArguments);
}
}
+1 -6
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see http://redis.io/commands/geoadd
@@ -40,9 +40,4 @@ class GEOADD extends RedisCommand
parent::setArguments($arguments);
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
+1 -6
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see http://redis.io/commands/geodist
@@ -26,9 +26,4 @@ class GEODIST extends RedisCommand
{
return 'GEODIST';
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
+1 -6
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see http://redis.io/commands/geohash
@@ -39,9 +39,4 @@ class GEOHASH extends RedisCommand
parent::setArguments($arguments);
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
+1 -6
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis;
use Predis\Command\PrefixableCommand as RedisCommand;
use Predis\Command\Command as RedisCommand;
/**
* @see http://redis.io/commands/geopos
@@ -39,9 +39,4 @@ class GEOPOS extends RedisCommand
parent::setArguments($arguments);
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}

Some files were not shown because too many files have changed in this diff Show More