mirror of
https://github.com/predis/predis.git
synced 2026-08-20 03:31:52 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 59b60a403e |
+1
-1
@@ -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
@@ -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
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: /
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
groups:
|
||||
github-actions:
|
||||
patterns:
|
||||
- "*"
|
||||
|
||||
- package-ecosystem: "composer"
|
||||
directory: /
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
groups:
|
||||
composer-minor:
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
@@ -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,24 +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
|
||||
- TLS_CLIENT_CNS=test_user
|
||||
- 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
|
||||
@@ -40,41 +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
|
||||
- sentinel
|
||||
|
||||
redis-cluster:
|
||||
image: ${REDIS_IMAGE_NAME:-redislabs/client-libs-test:8.0.2}
|
||||
image: ${REDIS_CLUSTER_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
|
||||
- TLS_CLIENT_CNS=test_user
|
||||
- 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"
|
||||
- "27379-27384:27379-27384"
|
||||
- "6372-6377:16379-16384"
|
||||
volumes:
|
||||
- "./dockers/cluster:/redis/work"
|
||||
profiles:
|
||||
@@ -89,33 +63,11 @@ 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:
|
||||
- all
|
||||
- clients
|
||||
- stack
|
||||
|
||||
sentinel:
|
||||
image: ${REDIS_IMAGE_NAME:-redislabs/client-libs-test:8.0.2}
|
||||
container_name: redis-sentinel
|
||||
depends_on:
|
||||
- redis-unprotected
|
||||
environment:
|
||||
- REDIS_CLUSTER=no
|
||||
- NODES=3
|
||||
- PORT=26379
|
||||
command: ${REDIS_EXTRA_ARGS:---sentinel}
|
||||
ports:
|
||||
- 26379:26379
|
||||
- 26380:26380
|
||||
- 26381:26381
|
||||
volumes:
|
||||
- "./dockers/sentinel.conf:/redis/config-default/redis.conf"
|
||||
- "./dockers/sentinel:/redis/work"
|
||||
profiles:
|
||||
- sentinel
|
||||
- all
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
sentinel resolve-hostnames yes
|
||||
sentinel monitor predis-test 127.0.0.1 6380 2
|
||||
# Be much more tolerant to transient stalls (index builds, GC, I/O)
|
||||
sentinel down-after-milliseconds predis-test 60000
|
||||
# Avoid rapid repeated failover attempts
|
||||
sentinel failover-timeout predis-test 180000
|
||||
# Keep it conservative: sync one replica at a time
|
||||
sentinel parallel-syncs predis-test 1
|
||||
@@ -1,8 +1,6 @@
|
||||
name-template: 'v$NEXT_MINOR_VERSION'
|
||||
tag-template: 'v$NEXT_MINOR_VERSION'
|
||||
change-template: '- $TITLE (#$NUMBER)'
|
||||
filter-by-commitish: true
|
||||
commitish: v3.x
|
||||
|
||||
autolabeler:
|
||||
- label: 'maintenance'
|
||||
|
||||
@@ -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/**'
|
||||
@@ -1,58 +0,0 @@
|
||||
ACLs
|
||||
AUTH
|
||||
Autoloading
|
||||
cafile
|
||||
CAS
|
||||
CN
|
||||
Customizable
|
||||
ElastiCache
|
||||
FPM
|
||||
GC
|
||||
IANA
|
||||
mTLS
|
||||
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
|
||||
@@ -7,7 +7,6 @@ on:
|
||||
branches:
|
||||
- main
|
||||
- v2.**
|
||||
- v3.**
|
||||
pull_request: null
|
||||
|
||||
permissions: {}
|
||||
@@ -24,7 +23,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Check file permissions
|
||||
run: test "$(find . -type f -not -path './.git/*' -executable)" = "./bin/create-command-test"
|
||||
@@ -47,7 +46,7 @@ jobs:
|
||||
tools: parallel-lint
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Check source code for syntax errors
|
||||
run: composer exec -- parallel-lint bin/ examples/ src/ tests/
|
||||
@@ -67,13 +66,13 @@ jobs:
|
||||
coverage: none
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Validate Composer configuration
|
||||
run: composer validate --no-interaction --strict
|
||||
|
||||
- name: Install dependencies
|
||||
uses: ramsey/composer-install@v4
|
||||
uses: ramsey/composer-install@v2
|
||||
with:
|
||||
dependency-versions: highest
|
||||
|
||||
@@ -101,7 +100,7 @@ jobs:
|
||||
coverage: none
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Check EditorConfig configuration
|
||||
run: test -f .editorconfig
|
||||
@@ -110,7 +109,7 @@ jobs:
|
||||
uses: greut/eclint-action@v0
|
||||
|
||||
- name: Install dependencies
|
||||
uses: ramsey/composer-install@v4
|
||||
uses: ramsey/composer-install@v2
|
||||
with:
|
||||
dependency-versions: highest
|
||||
|
||||
@@ -130,7 +129,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Check exported files
|
||||
run: |
|
||||
@@ -144,31 +143,25 @@ jobs:
|
||||
echo "EXPECTED=${EXPECTED}"
|
||||
test "${CURRENT}" = "${EXPECTED}"
|
||||
|
||||
changelog:
|
||||
|
||||
name: Changelog
|
||||
spelling:
|
||||
name: Spelling
|
||||
needs:
|
||||
- byte_level
|
||||
- syntax_errors
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
|
||||
if: >-
|
||||
github.event_name == 'pull_request' &&
|
||||
!contains(github.event.head_commit.message, 'nochangelog') &&
|
||||
!contains(github.event.head_commit.message, 'no-changelog') &&
|
||||
!contains(github.event.head_commit.message, 'no changelog') &&
|
||||
!contains(github.event.pull_request.labels.*.name, 'no-changelog')
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Check for CHANGELOG entry
|
||||
env:
|
||||
TARGET: ${{ github.event.pull_request.base.ref }}
|
||||
run: |
|
||||
FILES_CHANGED=$(git diff --name-only origin/$TARGET...HEAD | grep -E 'CHANGELOG\.md' -c)
|
||||
if [ "$FILES_CHANGED" != "1" ]; then
|
||||
echo "CHANGELOG.md was not updated";
|
||||
exit 1;
|
||||
fi;
|
||||
- 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
|
||||
|
||||
@@ -4,30 +4,21 @@ 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
|
||||
|
||||
steps:
|
||||
|
||||
- uses: release-drafter/release-drafter@v7
|
||||
- uses: release-drafter/release-drafter@v5
|
||||
with:
|
||||
config-name: release-drafter-config.yml
|
||||
env:
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
name: Spellcheck
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
check-spelling:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
checks: write
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
- name: Check Spelling
|
||||
uses: rojopolis/spellcheck-github-actions@0.62.0
|
||||
with:
|
||||
config_path: .github/spellcheck-settings.yml
|
||||
task_name: Markdown
|
||||
+29
-123
@@ -5,7 +5,6 @@ on:
|
||||
branches:
|
||||
- main
|
||||
- v2.**
|
||||
- v3.**
|
||||
pull_request:
|
||||
|
||||
concurrency:
|
||||
@@ -17,10 +16,6 @@ jobs:
|
||||
predis:
|
||||
name: PHP ${{ matrix.php }} (Redis ${{ matrix.redis }})
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
statuses: write
|
||||
pull-requests: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -32,13 +27,10 @@ jobs:
|
||||
- '8.4'
|
||||
redis:
|
||||
- '4.0'
|
||||
- '6.2'
|
||||
- '7.2'
|
||||
- '7.4'
|
||||
- '8.2'
|
||||
- '8.4'
|
||||
- '8.6'
|
||||
- '8.8'
|
||||
- '8.10'
|
||||
- '8.0'
|
||||
|
||||
steps:
|
||||
|
||||
@@ -46,24 +38,14 @@ jobs:
|
||||
run: |
|
||||
# Mapping of original redis versions to client test containers
|
||||
declare -A redis_clients_version_mapping=(
|
||||
["8.10"]="unstable-27987813126-debian"
|
||||
["8.8"]="8.8.0"
|
||||
["8.6"]="8.6.1"
|
||||
["8.4"]="8.4.0"
|
||||
["8.2"]="8.2.2"
|
||||
["8.0"]="8.0-M04-pre"
|
||||
["7.4"]="7.4.2"
|
||||
["7.2"]="7.2.7"
|
||||
)
|
||||
|
||||
# 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"]="6.2.17"
|
||||
)
|
||||
|
||||
if [[ -v redis_clients_version_mapping[${{ matrix.redis }}] ]]; then
|
||||
echo "REDIS_IMAGE_NAME=redislabs/client-libs-test:${redis_clients_version_mapping[${{ matrix.redis }}]}" >> $GITHUB_ENV
|
||||
echo "REDIS_STACK_IMAGE_NAME=redislabs/client-libs-test:${redis_stack_version_mapping[${{ matrix.redis }}]}" >> $GITHUB_ENV
|
||||
echo "DOCKER_SERVICE=redis-clients" >> $GITHUB_ENV
|
||||
|
||||
redis_major_version=$(echo "${{ matrix.redis }}" | grep -oP '^\d+')
|
||||
@@ -71,162 +53,86 @@ jobs:
|
||||
# Some configuration options available since Redis > 7
|
||||
if (( redis_major_version < 7 )); then
|
||||
echo "REDIS_EXTRA_ARGS="--tls-auth-clients optional --save ''"" >> $GITHUB_ENV
|
||||
else
|
||||
# Since 8.0 modules are bundled with core
|
||||
echo "REDIS_STACK_SERVER_PORT=6379" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
else
|
||||
echo "REDIS_IMAGE_NAME=redis:${{ matrix.redis }}" >> $GITHUB_ENV
|
||||
echo "DOCKER_SERVICE=redis-official" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Start Redis standalone image
|
||||
uses: hoverkraft-tech/compose-action@v3.0.0
|
||||
uses: hoverkraft-tech/compose-action@v2.0.1
|
||||
with:
|
||||
compose-file: .github/docker-compose.yml
|
||||
services: ${{ env.DOCKER_SERVICE }}
|
||||
|
||||
- name: Start Redis unprotected image
|
||||
uses: hoverkraft-tech/compose-action@v3.0.0
|
||||
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@v3.0.0
|
||||
if: ${{ matrix.redis >= '7.2' && matrix.redis < '8.0' }}
|
||||
uses: hoverkraft-tech/compose-action@v2.0.1
|
||||
if: ${{ matrix.redis == '7.4' }}
|
||||
with:
|
||||
compose-file: .github/docker-compose.yml
|
||||
services: redis-stack
|
||||
|
||||
- name: Start Redis cluster image
|
||||
id: cluster_infra
|
||||
uses: hoverkraft-tech/compose-action@v3.0.0
|
||||
if: ${{ matrix.redis > '4.0' }}
|
||||
uses: hoverkraft-tech/compose-action@v2.0.1
|
||||
if: ${{ matrix.redis == '7.4' }}
|
||||
with:
|
||||
compose-file: .github/docker-compose.yml
|
||||
services: redis-cluster
|
||||
|
||||
- name: Start Redis sentinels image
|
||||
id: sentinel_infra
|
||||
uses: hoverkraft-tech/compose-action@v3.0.0
|
||||
if: ${{ matrix.redis > '4.0' }}
|
||||
with:
|
||||
compose-file: .github/docker-compose.yml
|
||||
services: sentinel
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
extensions: relay-nightly
|
||||
coverage: ${{ (matrix.php == '8.4' && matrix.redis == '8.0') && 'xdebug' || 'none' }}
|
||||
extensions: relay
|
||||
coverage: ${{ (matrix.php == '8.1' && matrix.redis == '7.4') && 'xdebug' || 'none' }}
|
||||
|
||||
- name: Install Composer dependencies
|
||||
uses: ramsey/composer-install@v4
|
||||
uses: ramsey/composer-install@v2
|
||||
with:
|
||||
dependency-versions: highest
|
||||
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.1' || matrix.redis != '7.4' }}
|
||||
run: vendor/bin/phpunit
|
||||
|
||||
- name: Run tests with coverage
|
||||
if: ${{ matrix.php == '8.4' && matrix.redis == '8.0' }}
|
||||
run: vendor/bin/phpunit --coverage-php build/cov/coverage-predis.cov --coverage-filter ./src
|
||||
if: ${{ matrix.php == '8.1' && matrix.redis == '7.4' }}
|
||||
run: vendor/bin/phpunit --coverage-clover build/logs/clover-default.xml --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' }}
|
||||
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 sentinel tests
|
||||
if: ${{ (matrix.php != '8.4' || matrix.redis != '8.0') && matrix.redis > '4.0'}}
|
||||
run: vendor/bin/phpunit --group sentinel
|
||||
|
||||
- name: Run sentinel tests with coverage
|
||||
if: ${{ matrix.php == '8.4' && matrix.redis == '8.0' }}
|
||||
run: vendor/bin/phpunit --group sentinel --coverage-php build/cov/coverage-sentinel.cov --coverage-filter ./src
|
||||
if: ${{ matrix.php == '8.1' && matrix.redis == '7.4' }}
|
||||
run: vendor/bin/phpunit -c phpunit.relay.xml --coverage-clover build/logs/clover-relay.xml --coverage-filter ./src
|
||||
|
||||
- name: Run stack tests
|
||||
if: ${{ (matrix.php != '8.4' || matrix.redis != '8.0') && matrix.redis >= '7.2' }}
|
||||
if: ${{ matrix.redis == '7.4' }}
|
||||
run: vendor/bin/phpunit --group realm-stack
|
||||
|
||||
- name: Run stack tests with coverage
|
||||
if: ${{ matrix.php == '8.4' && matrix.redis == '8.0' }}
|
||||
run: vendor/bin/phpunit --group realm-stack --coverage-php build/cov/coverage-stack.cov --coverage-filter ./src
|
||||
|
||||
- name: Run stack tests using Relay
|
||||
if: ${{ (matrix.php != '8.4' || matrix.redis != '8.0') && matrix.redis >= '7.2' }}
|
||||
if: ${{ 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' }}
|
||||
run: vendor/bin/phpunit --group realm-stack -c phpunit.relay.xml --coverage-php build/cov/coverage-stack-relay.cov --coverage-filter ./src
|
||||
|
||||
- name: Run tests against cluster
|
||||
if: ${{ (matrix.php != '8.4' || matrix.redis != '8.0') && steps.cluster_infra.conclusion == 'success' }}
|
||||
if: ${{ matrix.redis == '7.4' }}
|
||||
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' }}
|
||||
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.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' }}
|
||||
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' }}
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
parallel: true
|
||||
|
||||
finish:
|
||||
name: Finish Coverall
|
||||
needs: predis
|
||||
if: ${{ always() }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
statuses: write
|
||||
pull-requests: write
|
||||
|
||||
steps:
|
||||
- name: Coveralls Finished
|
||||
uses: coverallsapp/github-action@v2
|
||||
with:
|
||||
parallel-finished: true
|
||||
env:
|
||||
COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
if: ${{ env.COVERALLS_REPO_TOKEN && matrix.php == '8.1' && matrix.redis == '7.4' }}
|
||||
run: |
|
||||
wget "https://github.com/php-coveralls/php-coveralls/releases/download/v2.5.3/php-coveralls.phar"
|
||||
php ./php-coveralls.phar -v
|
||||
|
||||
@@ -4,7 +4,7 @@ $PREDIS_HEADER = <<<EOS
|
||||
This file is part of the Predis package.
|
||||
|
||||
(c) 2009-2020 Daniele Alessandri
|
||||
(c) 2021-2026 Till Krüss
|
||||
(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.
|
||||
|
||||
+32
-167
@@ -1,172 +1,8 @@
|
||||
## Changelog
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Added
|
||||
- Make ZMSCORE command Prefixable and add to a ClusterStrategy (#1692)
|
||||
- Added support for new TS commands + Indonesian language support integration test (#1695)
|
||||
|
||||
### Fixed
|
||||
- Fixed Sentinel does not wipe servers on exception caused (#1694)
|
||||
- Fixed `@method cmsincrby()` annotation
|
||||
|
||||
## v3.5.1 (2026-06-11)
|
||||
### Added
|
||||
- Expose `pipeline()` API via `ClientInterface` (#1686)
|
||||
|
||||
### Fixed
|
||||
- Allow `UNLINK` to accept an array of keys (#1687)
|
||||
- Fixed `Client::(un)pack()` return types
|
||||
|
||||
## v3.5.0 (2026-06-02)
|
||||
### Added
|
||||
- Added support for `XNACK` command (#1666)
|
||||
- Added support for `INCREX` command (#1674)
|
||||
- Added support for `UNLINK` command (#1680)
|
||||
- Added support for `AR*` array commands (#1672)
|
||||
- Handle Redis Cluster `-READONLY` responses failover events (#1656)
|
||||
- Added `FPHA` argument for `JSON.SET` command (#1661)
|
||||
- Added new `COUNT` aggregator for Sorted Set commands (#1668)
|
||||
- Added support for multiple aggregators for `TS.range` commands (#1670)
|
||||
|
||||
### Changed
|
||||
- Include command name in unsupported container command error messages (#1653)
|
||||
|
||||
### Fixed
|
||||
- Fixed handling of gap slots in `SlotMap::offsetUnset()` (#1660)
|
||||
- Fixed `ZRANGE` to include 6.2 arguments (#1662)
|
||||
- Fixed Sentinel retry to narrow retryable exceptions to `CommunicationException` (#1665)
|
||||
- Fixed `SENTINEL SLAVES` RESP3 incompatible response (#1676)
|
||||
|
||||
## v3.4.2 (2026-03-09)
|
||||
### Changed
|
||||
- Switch to `static` closures
|
||||
|
||||
### Fixed
|
||||
- Fixed Sentinel `getParameters()` executed on string configuration (#1649)
|
||||
- Fixed Sentinel discovery methods not catching `StreamInitException` on connection failure (#1650)
|
||||
|
||||
## v3.4.1 (2026-02-23)
|
||||
### Added
|
||||
- Added `upstream_driver` option for CLIENT SETINFO upstream reporting (#1645)
|
||||
- Made `H(P)TTL` commands prefixable (#1639)
|
||||
- Made `(B)LMPOP` commands prefixable (#1643)
|
||||
|
||||
### Fixed
|
||||
- Fixed Sentinel `getParameter()` call on array error (#2423)
|
||||
- Removed deprecated `static` from callables (#1642)
|
||||
|
||||
## v3.4.0 (2026-02-11)
|
||||
### Added
|
||||
- Added optional retry support (#1616)
|
||||
- Added support for `VRANGE` command (#1623)
|
||||
- Added support for idempotent stream API (#1632)
|
||||
- Added support for `HOTKEYS` container command (#1630)
|
||||
|
||||
### Fixed
|
||||
- Fixed `[L|R]PUSHX` variadic arguments normalization (#1633)
|
||||
- Fixed wrong `@param` annotation in `Parameters` (#1614)
|
||||
- Made `ZRANDMEMBER` prefixable (#1621)
|
||||
- Improve connection handshake by pipelining commands (#1622)
|
||||
|
||||
## v3.3.0 (2025-11-24)
|
||||
### Added
|
||||
- Added cluster support for `XADD`, `XDEL` and `XRANGE` (#1587)
|
||||
- Added prefixable interface for `HEXPIRE` and `HEXPIRETIME` (#1592)
|
||||
- Added new experimental CAS/CAD functionality (#1609)
|
||||
- Added temporary `XREADGROUP_CLAIM` command (#1608)
|
||||
- Added support for `MSET` command (#1610)
|
||||
- Added experimental support for `FT.HYBRID` (#1607)
|
||||
|
||||
### Changed
|
||||
- Improved compatiblity with Relay (#1597)
|
||||
- Refactor pipeline data writing depends on connection type (#1586)
|
||||
|
||||
## 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)
|
||||
|
||||
### 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)
|
||||
|
||||
## v2.4.0 (2025-04-30)
|
||||
### Added
|
||||
- Added new hash-field expiration commands (#1520)
|
||||
- Added missing `FT._LIST` and `BITFIELD_RO` commands (#1521)
|
||||
|
||||
### Changed
|
||||
- Update `WATCH` command to accept `string|string[]` (#1476)
|
||||
- Optimize cluster slotmap with compact slot range object (#1493)
|
||||
|
||||
### Fixed
|
||||
- Fixed `EVAL_RO` cluster support (#1449)
|
||||
- Fixed PHP 8.4 compatibility with `stream_context_set_option()` (#1503)
|
||||
- Prevent named arguments runtime failure (#1509)
|
||||
- Mark `GEOSEARCH` as read-only to ensure execution on replica (#1481)
|
||||
- Fixed protocol loss during redis cluster `MOVED` / `ASK` (#1530)
|
||||
|
||||
### Maintenance
|
||||
- Added CI testing with Redis 8.0 (#1510)
|
||||
- Added test coverage for compatibility with Redis 8.0 (#1513)
|
||||
- Use parallel on PHP-CS-Fixer (#1489)
|
||||
- Fixed PHP 8.4 compatibility with `stream_context_set_option()`
|
||||
|
||||
## v2.3.0 (2024-11-21)
|
||||
### Added
|
||||
@@ -182,7 +18,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).
|
||||
|
||||
@@ -81,17 +81,65 @@ An exception to this rule is [`SORT`](http://redis.io/commands/sort) for which m
|
||||
|
||||
## When should I use Relay? ##
|
||||
|
||||
If you care about performance, __always__. [Relay][relay] is free to use.
|
||||
If you care about performance, __always__. [Relay](https://github.com/cachewerk/relay) is free to use.
|
||||
|
||||
## When should I use PhpRedis? ###
|
||||
|
||||
Predis is fast enough when Redis is located on the same machine as PHP.
|
||||
Predis is fast enough when Redis is located on the same machine as PHP, more on that later.
|
||||
|
||||
[PhpRedis][phpredis] and [Relay][relay] perform significantly better when network I/O is involved,
|
||||
due to its ability to compress data by ~75%. Fewer bytes and received sent over the network
|
||||
[means faster operations][performance], and potentially cost savings when network traffic isn't
|
||||
free (e.g. AWS ElastiCache Inter-AZ transfer costs).
|
||||
[PhpRedis](https://github.com/phpredis/phpredis) (and Relay) perform significantly better when
|
||||
network I/O is involved, due to their ability to compress data by ~75%. Fewer bytes and received
|
||||
sent over the network [means faster operations](https://akalongman.medium.com/phpredis-vs-predis-comparison-on-real-production-data-a819b48cbadb),
|
||||
and potentially cost savings when network traffic isn't free (e.g. AWS ElastiCache Inter-AZ transfer costs).
|
||||
|
||||
[phpredis]: https://github.com/phpredis/phpredis
|
||||
[relay]: [https://github.com/phpredis/phpredis](https://github.com/cachewerk/relay)
|
||||
[performance]: https://akalongman.medium.com/phpredis-vs-predis-comparison-on-real-production-data-a819b48cbadb
|
||||
## Predis is a pure-PHP implementation: it can not be fast enough! ##
|
||||
|
||||
It really depends, but most of the times the answer is: _yes, it is fast enough_. I will give you a
|
||||
couple of easy numbers with a simple test that uses a single client and is executed by PHP 5.5.6
|
||||
against a local instance of Redis 2.8 that runs under Ubuntu 13.10 on a Intel Q6600:
|
||||
|
||||
```
|
||||
21000 SET/sec using 12 bytes for both key and value.
|
||||
21000 GET/sec while retrieving the very same values.
|
||||
0.130 seconds to fetch 30000 keys using _KEYS *_.
|
||||
```
|
||||
|
||||
How does it compare with [__PhpRedis__](http://github.com/phpredis/phpredis), a nice C extension
|
||||
providing an efficient client for Redis?
|
||||
|
||||
```
|
||||
30100 SET/sec using 12 bytes for both key and value
|
||||
29400 GET/sec while retrieving the very same values
|
||||
0.035 seconds to fetch 30000 keys using "KEYS *"".
|
||||
```
|
||||
|
||||
Wow __PhpRedis__ seems much faster! Well, we are comparing a C extension with a pure-PHP library so
|
||||
lower numbers are quite expected but there is a fundamental flaw in them: is this really how you are
|
||||
going to use Redis in your application? Are you really going to send thousands of commands using a
|
||||
for-loop on each page request using a single client instance? If so... well I guess you are probably
|
||||
doing something wrong. Also, if you need to `SET` or `GET` multiple keys you should definitely use
|
||||
commands such as `MSET` and `MGET`. You can also use pipelining to get more performances when this
|
||||
technique can be used.
|
||||
|
||||
There is one more thing: we have tested the overhead of Predis by connecting on a localhost instance
|
||||
of Redis but how these numbers change when we hit the physical network by connecting to remote Redis
|
||||
instances?
|
||||
|
||||
```
|
||||
Using Predis:
|
||||
3200 SET/sec using 12 bytes for both key and value
|
||||
3200 GET/sec while retrieving the very same values
|
||||
0.132 seconds to fetch 30000 keys using "KEYS *".
|
||||
|
||||
Using PhpRedis:
|
||||
3500 SET/sec using 12 bytes for both key and value
|
||||
3500 GET/sec while retrieving the very same values
|
||||
0.045 seconds to fetch 30000 keys using "KEYS *".
|
||||
```
|
||||
|
||||
There you go, you get almost the same average numbers and the reason is simple: network latency is a
|
||||
real performance killer and you cannot do (almost) anything about that. As a disclaimer, remember
|
||||
that we are measuring the overhead of client libraries implementations and the effects of network
|
||||
round-trip times, so we are not really measuring how fast Redis is. Redis shines best with thousands
|
||||
of concurrent clients doing requests! Also, actual performances should be measured according to how
|
||||
your application will use Redis.
|
||||
|
||||
@@ -14,7 +14,7 @@ More details about this project can be found on the [frequently asked questions]
|
||||
|
||||
## Main features ##
|
||||
|
||||
- Support for Redis from __3.0__ to __8.0__.
|
||||
- Support for Redis from __3.0__ to __7.4__.
|
||||
- Support for clustering using client-side sharding and pluggable keyspace distributors.
|
||||
- Support for [redis-cluster](http://redis.io/topics/cluster-tutorial) (Redis >= 3.0).
|
||||
- Support for master-slave replication setups and [redis-sentinel](http://redis.io/topics/sentinel).
|
||||
@@ -114,40 +114,6 @@ The connection schemes [`redis`](http://www.iana.org/assignments/uri-schemes/pro
|
||||
also supported, with the difference that URI strings containing these schemes are parsed following
|
||||
the rules described on their respective IANA provisional registration documents.
|
||||
|
||||
Since Redis 8.6, you can authenticate a client using the Subject CN from its TLS client certificate (mTLS).
|
||||
When this is enabled on the server, the client is authenticated during the TLS handshake, so you don’t need
|
||||
to send an AUTH command.
|
||||
|
||||
To use this, configure:
|
||||
|
||||
- a CA certificate used to verify the server certificate (cafile),
|
||||
- a client certificate (local_cert) signed by a CA trusted by the Redis server for client authentication,
|
||||
- the corresponding private key (local_pk).
|
||||
|
||||
Make sure:
|
||||
|
||||
- the Redis server certificate is signed by a CA trusted by the client, and
|
||||
- the client certificate is signed by a CA trusted by the Redis server (mTLS).
|
||||
|
||||
```php
|
||||
// Named array of connection parameters:
|
||||
$client = new Predis\Client([
|
||||
'scheme' => 'tls',
|
||||
'ssl' => [
|
||||
'cafile' => 'ca.pem', // CA used to verify the server certificate
|
||||
'local_cert' => 'client.crt', // client certificate (Subject CN maps to ACL user)
|
||||
'local_pk' => 'client.key', // client private key
|
||||
'verify_peer' => true,
|
||||
],
|
||||
]);
|
||||
|
||||
// ACL user must exist and match the certificate Subject CN (example: CN=CN_NAME).
|
||||
// Enable the user and grant permissions as needed:
|
||||
$client->acl->setUser('CN_NAME', 'on', '>clientpass', 'allcommands', 'allkeys')
|
||||
|
||||
echo $client->acl->whoami() // CN_NAME
|
||||
```
|
||||
|
||||
The actual list of supported connection parameters can vary depending on each connection backend so
|
||||
it is recommended to refer to their specific documentation or implementation for details.
|
||||
|
||||
@@ -172,50 +138,6 @@ it is still desired to have control of when the connection is opened or closed:
|
||||
achieved by invoking `$client->connect()` and `$client->disconnect()`. Please note that the effect
|
||||
of these methods on aggregate connections may differ depending on each specific implementation.
|
||||
|
||||
#### Persistent connections ####
|
||||
|
||||
To increase a performance of your application you may set up a client to use persistent TCP connection, this way
|
||||
client saves a time on socket creation and connection handshake. By default, connection is created on first-command
|
||||
execution and will be automatically closed by GC before the process is being killed.
|
||||
However, if your application is backed by PHP-FPM the processes are idle, and you may set up it to be persistent and
|
||||
reusable across multiple script execution within the same process.
|
||||
|
||||
To enable the persistent connection mode you should provide following configuration:
|
||||
|
||||
```php
|
||||
// Standalone
|
||||
$client = new Predis\Client(['persistent' => true]);
|
||||
|
||||
// Cluster
|
||||
$client = new Predis\Client(
|
||||
['tcp://host:port', 'tcp://host:port', 'tcp://host:port'],
|
||||
['cluster' => 'redis', 'parameters' => ['persistent' => true]]
|
||||
);
|
||||
```
|
||||
|
||||
**Important**
|
||||
|
||||
If you operate on multiple clients within the same application, and they communicate with the same resource, by default
|
||||
they will share the same socket (that's the default behaviour of persistent sockets). So in this case you would need
|
||||
to additionally provide a `conn_uid` identifier for each client, this way each client will create its own socket so
|
||||
the connection context won't be shared across clients. This socket behaviour explained
|
||||
[here](https://www.php.net/manual/en/function.stream-socket-client.php#105393)
|
||||
|
||||
```php
|
||||
// Standalone
|
||||
$client1 = new Predis\Client(['persistent' => true, 'conn_uid' => 'id_1']);
|
||||
$client2 = new Predis\Client(['persistent' => true, 'conn_uid' => 'id_2']);
|
||||
|
||||
// Cluster
|
||||
$client1 = new Predis\Client(
|
||||
['tcp://host:port', 'tcp://host:port', 'tcp://host:port'],
|
||||
['cluster' => 'redis', 'parameters' => ['persistent' => true, 'conn_uid' => 'id_1']]
|
||||
);
|
||||
$client2 = new Predis\Client(
|
||||
['tcp://host:port', 'tcp://host:port', 'tcp://host:port'],
|
||||
['cluster' => 'redis', 'parameters' => ['persistent' => true, 'conn_uid' => 'id_2']]
|
||||
);
|
||||
```
|
||||
|
||||
### Client configuration ###
|
||||
|
||||
@@ -237,7 +159,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.
|
||||
@@ -279,26 +200,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
|
||||
@@ -414,25 +315,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 ###
|
||||
|
||||
@@ -543,186 +425,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.
|
||||
|
||||
### Retry exceptions
|
||||
|
||||
You can enable automatic retry that is disabled by default, to be able to reduce the amount of
|
||||
false-positives in case of network issues. By default, we're retrying on any connection,
|
||||
timeout or socket initialization exception, but you can update the list of retry
|
||||
exceptions. For now `EqualBackoff` and `ExponentialBackoff` strategies are available,
|
||||
but you may provide your custom one. Retry may be configured with any type of communication
|
||||
(standalone node, cluster, pipeline, transaction, replication). Here's an example of
|
||||
configuration:
|
||||
|
||||
```php
|
||||
// Standalone client
|
||||
$client = new Predis\Client([
|
||||
'retry' => new \Predis\Retry\Retry(
|
||||
new \Predis\Retry\Strategy\ExponentialBackoff(1000, 10000), // Base and cap configuration in microseconds
|
||||
3 // Number of retries
|
||||
),
|
||||
]);
|
||||
|
||||
// Cluster configuration
|
||||
$options = [
|
||||
'parameters' => [
|
||||
'retry' => new \Predis\Retry\Retry(new \Predis\Retry\Strategy\ExponentialBackoff(1000, 10000), 3),
|
||||
],
|
||||
];
|
||||
|
||||
$client = new Predis\Client(['tcp://host:port', 'tcp://host:port', 'tcp://host:port'], $options);
|
||||
|
||||
$retry = new \Predis\Retry\Retry(
|
||||
new \Predis\Retry\Strategy\ExponentialBackoff(1000, 10000),
|
||||
3
|
||||
);
|
||||
|
||||
// Update a list of exceptions to catch
|
||||
$retry->updateCatchableExceptions([Exception::class]);
|
||||
```
|
||||
|
||||
## 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(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 ##
|
||||
|
||||
|
||||
|
||||
@@ -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:
|
||||
//
|
||||
|
||||
+3
-11
@@ -22,14 +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/phpcov": "^6.0 || ^8.0"
|
||||
"phpunit/phpunit": "^8.0 || ^9.4"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-relay": "Faster connection with in-memory caching (>=0.6.2)"
|
||||
@@ -46,13 +44,7 @@
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true,
|
||||
"preferred-install": "dist",
|
||||
"audit": {
|
||||
"ignore": [
|
||||
"GHSA-vvj3-c3rp-c85p",
|
||||
"PKSA-z3gr-8qht-p93v"
|
||||
]
|
||||
}
|
||||
"preferred-install": "dist"
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
@@ -40,7 +40,7 @@ class NaiveDistributor implements DistributorInterface, HashGeneratorInterface
|
||||
|
||||
public function remove($node)
|
||||
{
|
||||
$this->nodes = array_filter($this->nodes, static function ($n) use ($node) {
|
||||
$this->nodes = array_filter($this->nodes, function ($n) use ($node) {
|
||||
return $n !== $node;
|
||||
});
|
||||
|
||||
@@ -89,7 +89,7 @@ class NaiveDistributor implements DistributorInterface, HashGeneratorInterface
|
||||
}
|
||||
|
||||
$options = [
|
||||
'cluster' => static function () {
|
||||
'cluster' => function () {
|
||||
$distributor = new NaiveDistributor();
|
||||
$strategy = new PredisStrategy($distributor);
|
||||
$cluster = new PredisCluster($strategy);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
@@ -34,11 +34,11 @@ class SimpleDebuggableConnection extends StreamConnection
|
||||
|
||||
private function storeDebug(CommandInterface $command, $direction)
|
||||
{
|
||||
$firstArg = $command->getArgument(0);
|
||||
$firtsArg = $command->getArgument(0);
|
||||
$timestamp = round(microtime(true) - $this->tstart, 4);
|
||||
|
||||
$debug = $command->getId();
|
||||
$debug .= isset($firstArg) ? " $firstArg " : ' ';
|
||||
$debug .= isset($firtsArg) ? " $firtsArg " : ' ';
|
||||
$debug .= "$direction $this";
|
||||
$debug .= " [{$timestamp}s]";
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
@@ -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
|
||||
@@ -62,7 +62,7 @@ class EventsListener implements Countable
|
||||
$dispatcher->attachCallback('events', $events = new EventsListener());
|
||||
|
||||
// Attach a function to control the dispatcher loop termination with a message.
|
||||
$dispatcher->attachCallback('control', static function ($payload, $dispatcher) {
|
||||
$dispatcher->attachCallback('control', function ($payload, $dispatcher) {
|
||||
if ($payload === 'terminate_dispatcher') {
|
||||
$dispatcher->stop();
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
@@ -18,7 +18,7 @@ require __DIR__ . '/shared.php';
|
||||
|
||||
$client = new Predis\Client($single_server);
|
||||
|
||||
$responses = $client->pipeline(static function ($pipe) {
|
||||
$responses = $client->pipeline(function ($pipe) {
|
||||
$pipe->flushdb();
|
||||
$pipe->incrby('counter', 10);
|
||||
$pipe->incrby('counter', 30);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 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-2026 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";
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
@@ -23,7 +23,7 @@ $pubsub = $client->pubSubLoop();
|
||||
|
||||
// When using Relay you cannot use foreach-loops to iterate
|
||||
// over messages instead use a callback function
|
||||
$poorMansKafka = static function ($message, $client) {
|
||||
$poorMansKafka = function ($message, $client) {
|
||||
switch ($message->kind) {
|
||||
case 'subscribe':
|
||||
echo "Subscribed to {$message->channel}", PHP_EOL;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
@@ -56,7 +56,7 @@ $options = [
|
||||
'commands' => [
|
||||
'hmgetall' => 'HashMultipleGetAll',
|
||||
],
|
||||
'replication' => static function () {
|
||||
'replication' => function () {
|
||||
$strategy = new ReplicationStrategy();
|
||||
$strategy->setScriptReadOnly(HashMultipleGetAll::BODY);
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 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', static 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;
|
||||
@@ -1,64 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 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;
|
||||
+3
-3
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
@@ -22,9 +22,9 @@ function redis_version($info)
|
||||
return $info['Server']['redis_version'];
|
||||
} elseif (isset($info['redis_version'])) {
|
||||
return $info['redis_version'];
|
||||
} else {
|
||||
return 'unknown version';
|
||||
}
|
||||
|
||||
return 'unknown version';
|
||||
}
|
||||
|
||||
$single_server = [
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
@@ -35,7 +35,7 @@ function zpop($client, $key)
|
||||
// which the client bails out with an exception.
|
||||
];
|
||||
|
||||
$client->transaction($options, static function ($tx) use ($key, &$element) {
|
||||
$client->transaction($options, function ($tx) use ($key, &$element) {
|
||||
@[$element] = $tx->zrange($key, 0, 0);
|
||||
|
||||
if (isset($element)) {
|
||||
|
||||
@@ -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,9 +29,15 @@ 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
|
||||
- message: "#^Variable \\$response might not be defined\\.$#"
|
||||
count: 2
|
||||
path: src/Connection/Cluster/RedisCluster.php
|
||||
- message: "#^Access to an undefined property Predis\\\\Connection\\\\ParametersInterface\\:\\:\\$role\\.$#"
|
||||
count: 1
|
||||
path: src/Connection/Replication/MasterSlaveReplication.php
|
||||
@@ -42,3 +51,6 @@ parameters:
|
||||
- message: "#^Variable \\$response might not be defined\\.$#"
|
||||
count: 1
|
||||
path: src/Connection/Replication/MasterSlaveReplication.php
|
||||
- message: "#^Variable \\$response might not be defined\\.$#"
|
||||
count: 1
|
||||
path: src/Connection/Replication/SentinelReplication.php
|
||||
|
||||
+4
-13
@@ -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_STACK_SERVER_PORT" value="6479" />
|
||||
<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>
|
||||
|
||||
+12
-38
@@ -10,9 +10,6 @@
|
||||
stopOnFailure="false"
|
||||
beStrictAboutTestsThatDoNotTestAnything="true"
|
||||
>
|
||||
<php>
|
||||
<ini name="error_reporting" value="E_ALL & ~E_DEPRECATED"/>
|
||||
</php>
|
||||
|
||||
<testsuites>
|
||||
<testsuite name="Predis Test Suite">
|
||||
@@ -20,20 +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>sentinel</group>
|
||||
<!-- <group>connected</group> -->
|
||||
<!-- <group>disconnected</group> -->
|
||||
<!-- <group>commands</group> -->
|
||||
@@ -50,38 +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_STACK_SERVER_PORT" value="6479" />
|
||||
<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" />
|
||||
|
||||
<!-- Sentinel -->
|
||||
<const name="REDIS_SENTINEL_SERVICE" value="predis-test" />
|
||||
<const
|
||||
name="REDIS_SENTINEL_ENDPOINTS"
|
||||
value="127.0.0.1:26379,127.0.0.1:26380,127.0.0.1:26381"
|
||||
/>
|
||||
|
||||
<!-- SSL -->
|
||||
<env name="STANDALONE_CA_CERT_PATH" value=".github/dockers/standalone/tls/ca.crt" />
|
||||
<env name="STANDALONE_LOCAL_CERT_PATH" value=".github/dockers/standalone/tls/test_user.crt" />
|
||||
<env name="STANDALONE_LOCAL_PK_PATH" value=".github/dockers/standalone/tls/test_user.key" />
|
||||
<env name="CN_USER_NAME" value="test_user" />
|
||||
<env name="REDIS_SSL_PORT" value="6666" />
|
||||
<env name="CLUSTER_CA_CERT_PATH" value=".github/dockers/cluster/tls/ca.crt" />
|
||||
<env name="CLUSTER_LOCAL_CERT_PATH" value=".github/dockers/cluster/tls/test_user.crt" />
|
||||
<env name="CLUSTER_LOCAL_PK_PATH" value=".github/dockers/cluster/tls/test_user.key" />
|
||||
<const
|
||||
name="SSL_REDIS_CLUSTER_ENDPOINTS"
|
||||
value="127.0.0.1:27379?password=foobar,127.0.0.1:27380?password=foobar,127.0.0.1:27381?password=foobar"
|
||||
/>
|
||||
|
||||
<!-- 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>
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
+18
-48
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
@@ -16,33 +16,30 @@ 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;
|
||||
use Predis\Connection\AggregateConnectionInterface;
|
||||
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;
|
||||
use Predis\Transaction\MultiExec as MultiExecTransaction;
|
||||
use ReturnTypeWillChange;
|
||||
use RuntimeException;
|
||||
use Throwable;
|
||||
use Traversable;
|
||||
|
||||
/**
|
||||
@@ -56,7 +53,7 @@ use Traversable;
|
||||
*/
|
||||
class Client implements ClientInterface, IteratorAggregate
|
||||
{
|
||||
public const VERSION = '3.5.1';
|
||||
public const VERSION = '2.3.1-dev';
|
||||
|
||||
/** @var OptionsInterface */
|
||||
private $options;
|
||||
@@ -92,8 +89,9 @@ class Client implements ClientInterface, IteratorAggregate
|
||||
return new Options($options);
|
||||
} elseif ($options instanceof OptionsInterface) {
|
||||
return $options;
|
||||
} else {
|
||||
throw new InvalidArgumentException('Invalid type for client options');
|
||||
}
|
||||
throw new InvalidArgumentException('Invalid type for client options');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -139,10 +137,11 @@ class Client implements ClientInterface, IteratorAggregate
|
||||
return $initializer($parameters, true);
|
||||
} elseif ($options->defined('aggregate') && $initializer = $options->aggregate) {
|
||||
return $initializer($parameters, false);
|
||||
} else {
|
||||
throw new InvalidArgumentException(
|
||||
'Array of connection parameters requires `cluster`, `replication` or `aggregate` client option'
|
||||
);
|
||||
}
|
||||
throw new InvalidArgumentException(
|
||||
'Array of connection parameters requires `cluster`, `replication` or `aggregate` client option'
|
||||
);
|
||||
}
|
||||
|
||||
if (is_callable($parameters)) {
|
||||
@@ -272,8 +271,8 @@ class Client implements ClientInterface, IteratorAggregate
|
||||
/**
|
||||
* Applies the configured serializer and compression to given value.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return mixed
|
||||
* @param mixed $value
|
||||
* @return string
|
||||
*/
|
||||
public function pack($value)
|
||||
{
|
||||
@@ -285,8 +284,8 @@ class Client implements ClientInterface, IteratorAggregate
|
||||
/**
|
||||
* Deserializes and decompresses to given value.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return mixed
|
||||
* @param mixed $value
|
||||
* @return string
|
||||
*/
|
||||
public function unpack($value)
|
||||
{
|
||||
@@ -376,24 +375,10 @@ class Client implements ClientInterface, IteratorAggregate
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @throws Throwable
|
||||
*/
|
||||
public function executeCommand(CommandInterface $command)
|
||||
{
|
||||
$parameters = $this->connection->getParameters();
|
||||
|
||||
if ($this->connection instanceof AggregateConnectionInterface || $this->connection instanceof RelayConnection) {
|
||||
$response = $this->connection->executeCommand($command);
|
||||
} else {
|
||||
$response = $parameters->retry->callWithRetry(
|
||||
function () use ($command) {
|
||||
return $this->connection->executeCommand($command);
|
||||
},
|
||||
function () {
|
||||
$this->connection->disconnect();
|
||||
}
|
||||
);
|
||||
}
|
||||
$response = $this->connection->executeCommand($command);
|
||||
|
||||
if ($response instanceof ResponseInterface) {
|
||||
if ($response instanceof ErrorResponseInterface) {
|
||||
@@ -403,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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -568,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.
|
||||
*
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
@@ -19,7 +19,6 @@ use Predis\Command\Argument\Search\AlterArguments;
|
||||
use Predis\Command\Argument\Search\CreateArguments;
|
||||
use Predis\Command\Argument\Search\DropArguments;
|
||||
use Predis\Command\Argument\Search\ExplainArguments;
|
||||
use Predis\Command\Argument\Search\HybridSearch\HybridSearchQuery;
|
||||
use Predis\Command\Argument\Search\ProfileArguments;
|
||||
use Predis\Command\Argument\Search\SchemaFields\FieldInterface;
|
||||
use Predis\Command\Argument\Search\SearchArguments;
|
||||
@@ -37,27 +36,20 @@ use Predis\Command\Argument\TimeSeries\IncrByArguments;
|
||||
use Predis\Command\Argument\TimeSeries\InfoArguments;
|
||||
use Predis\Command\Argument\TimeSeries\MGetArguments;
|
||||
use Predis\Command\Argument\TimeSeries\MRangeArguments;
|
||||
use Predis\Command\Argument\TimeSeries\NRangeArguments;
|
||||
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\HOTKEYS;
|
||||
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\HSETEX;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Interface defining a client-side context such as a pipeline or transaction.
|
||||
*
|
||||
* @method $this copy(string $source, string $destination, int $db = -1, bool $replace = false)
|
||||
* @method $this del(array|string $keys)
|
||||
* @method $this delex(string $key, string $flag, $flagValue)
|
||||
* @method $this digest(string $key)
|
||||
* @method $this dump($key)
|
||||
* @method $this exists($key)
|
||||
* @method $this expire($key, $seconds, string $expireOption = '')
|
||||
@@ -67,8 +59,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)
|
||||
@@ -78,26 +70,7 @@ use Predis\Command\Redis\VADD;
|
||||
* @method $this sort_ro(string $key, ?string $byPattern = null, ?LimitOffsetCount $limit = null, array $getPatterns = [], ?string $sorting = null, bool $alpha = false)
|
||||
* @method $this ttl($key)
|
||||
* @method $this type($key)
|
||||
* @method $this unlink(string[]|string $keyOrKeys, string ...$keys = null)
|
||||
* @method $this append($key, $value)
|
||||
* @method $this arcount(string $key)
|
||||
* @method $this ardel(string $key, int ...$index)
|
||||
* @method $this ardelrange(string $key, int ...$startEnd)
|
||||
* @method $this arget(string $key, int $index)
|
||||
* @method $this argetrange(string $key, int $start, int $end)
|
||||
* @method $this argrep(string $key, int $start, int $end, array $predicates, ?string $combinator = null, ?int $limit = null, bool $withValues = false, bool $noCase = false)
|
||||
* @method $this arinfo(string $key, bool $full = false)
|
||||
* @method $this arinsert(string $key, string ...$value)
|
||||
* @method $this arlastitems(string $key, int $count, bool $reverse = false)
|
||||
* @method $this arlen(string $key)
|
||||
* @method $this armget(string $key, int ...$index)
|
||||
* @method $this armset(string $key, array $indexValueDictionary)
|
||||
* @method $this arnext(string $key)
|
||||
* @method $this arop(string $key, int $start, int $end, string $operation, $matchValue = null)
|
||||
* @method $this arring(string $key, int $size, string ...$value)
|
||||
* @method $this arscan(string $key, int $start, int $end, ?int $limit = null)
|
||||
* @method $this arseek(string $key, int $index)
|
||||
* @method $this arset(string $key, int $index, string ...$value)
|
||||
* @method $this bfadd(string $key, $item)
|
||||
* @method $this bfexists(string $key, $item)
|
||||
* @method $this bfinfo(string $key, string $modifier = '')
|
||||
@@ -110,7 +83,6 @@ use Predis\Command\Redis\VADD;
|
||||
* @method $this bitcount(string $key, $start = null, $end = null, string $index = 'byte')
|
||||
* @method $this bitop($operation, $destkey, $key)
|
||||
* @method $this bitfield($key, $subcommand, ...$subcommandArg)
|
||||
* @method $this bitfield_ro(string $key, ?array $encodingOffsetMap = null)
|
||||
* @method $this bitpos($key, $bit, $start = null, $end = null, string $index = 'byte')
|
||||
* @method $this blmpop(int $timeout, array $keys, string $modifier = 'left', int $count = 1)
|
||||
* @method $this bzpopmax(array $keys, int $timeout)
|
||||
@@ -128,7 +100,7 @@ use Predis\Command\Redis\VADD;
|
||||
* @method $this cfinsertnx(string $key, int $capacity = -1, bool $noCreate = false, string ...$item)
|
||||
* @method $this cfreserve(string $key, int $capacity, int $bucketSize = -1, int $maxIterations = -1, int $expansion = -1)
|
||||
* @method $this cfscandump(string $key, int $iterator)
|
||||
* @method $this cmsincrby(string $key, string|int ...$itemIncrementDictionary)
|
||||
* @method $this cmsincrby(string $key, string|int...$itemIncrementDictionary)
|
||||
* @method $this cmsinfo(string $key)
|
||||
* @method $this cmsinitbydim(string $key, int $width, int $depth)
|
||||
* @method $this cmsinitbyprob(string $key, float $errorRate, float $probability)
|
||||
@@ -139,7 +111,6 @@ use Predis\Command\Redis\VADD;
|
||||
* @method $this failover(?To $to = null, bool $abort = false, int $timeout = -1)
|
||||
* @method $this fcall(string $function, array $keys, ...$args)
|
||||
* @method $this fcall_ro(string $function, array $keys, ...$args)
|
||||
* @method $this ft_list()
|
||||
* @method $this ftaggregate(string $index, string $query, ?AggregateArguments $arguments = null)
|
||||
* @method $this ftaliasadd(string $alias, string $index)
|
||||
* @method $this ftaliasdel(string $alias)
|
||||
@@ -151,7 +122,6 @@ use Predis\Command\Redis\VADD;
|
||||
* @method $this ftdictdump(string $dict)
|
||||
* @method $this ftdropindex(string $index, ?DropArguments $arguments = null)
|
||||
* @method $this ftexplain(string $index, string $query, ?ExplainArguments $arguments = null)
|
||||
* @method $this fthybrid(string $index, HybridSearchQuery $query)
|
||||
* @method $this ftinfo(string $index)
|
||||
* @method $this ftprofile(string $index, ProfileArguments $arguments)
|
||||
* @method $this ftsearch(string $index, string $query, ?SearchArguments $arguments = null)
|
||||
@@ -172,13 +142,11 @@ use Predis\Command\Redis\VADD;
|
||||
* @method $this incr($key)
|
||||
* @method $this incrby($key, $increment)
|
||||
* @method $this incrbyfloat($key, $increment)
|
||||
* @method $this increx(string $key, int|float|string $value, ?int $lbound = null, ?int $ubound = null, bool $saturate = false, ?string $expireType = null, $expireValue = null, bool $enx = false)
|
||||
* @method $this mget(array $keys)
|
||||
* @method $this mset(array $dictionary)
|
||||
* @method $this msetex(array $dictionary, ?string $existModifier = null, ?string $expireResolution = null, ?int $expireTTL = null)
|
||||
* @method $this msetnx(array $dictionary)
|
||||
* @method $this psetex($key, $milliseconds, $value)
|
||||
* @method $this set($key, $value, $expireResolution = null, $expireTTL = null, $flag = null, $flagValue = null)
|
||||
* @method $this set($key, $value, $expireResolution = null, $expireTTL = null, $flag = null)
|
||||
* @method $this setbit($key, $offset, $value)
|
||||
* @method $this setex($key, $seconds, $value)
|
||||
* @method $this setnx($key, $value)
|
||||
@@ -194,9 +162,7 @@ use Predis\Command\Redis\VADD;
|
||||
* @method $this hpexpireat(string $key, int $unixTimeMilliseconds, array $fields, string $flag = null)
|
||||
* @method $this hpexpiretime(string $key, array $fields)
|
||||
* @method $this hget($key, $field)
|
||||
* @method $this hgetex(string $key, array $fields, string $modifier = HGETEX::NULL)
|
||||
* @method $this hgetall($key)
|
||||
* @method $this hgetdel(string $key, array $fields)
|
||||
* @method $this hincrby($key, $field, $increment)
|
||||
* @method $this hincrbyfloat($key, $field, $increment)
|
||||
* @method $this hkeys($key)
|
||||
@@ -206,7 +172,6 @@ use Predis\Command\Redis\VADD;
|
||||
* @method $this hrandfield(string $key, int $count = 1, bool $withValues = false)
|
||||
* @method $this hscan($key, $cursor, ?array $options = null)
|
||||
* @method $this hset($key, $field, $value)
|
||||
* @method $this hsetex(string $key, array $fieldValueMap, string $setModifier = HSETEX::SET_NULL, string $ttlModifier = HSETEX::TTL_NULL, int|bool $ttlModifierValue = false)
|
||||
* @method $this hsetnx($key, $field, $value)
|
||||
* @method $this httl(string $key, array $fields)
|
||||
* @method $this hpttl(string $key, array $fields)
|
||||
@@ -229,7 +194,7 @@ use Predis\Command\Redis\VADD;
|
||||
* @method $this jsonobjkeys(string $key, string $path = '$')
|
||||
* @method $this jsonobjlen(string $key, string $path = '$')
|
||||
* @method $this jsonresp(string $key, string $path = '$')
|
||||
* @method $this jsonset(string $key, string $path, string $value, ?string $subcommand = null, ?string $fpha = null)
|
||||
* @method $this jsonset(string $key, string $path, string $value, ?string $subcommand = null)
|
||||
* @method $this jsonstrappend(string $key, string $path, string $value)
|
||||
* @method $this jsonstrlen(string $key, string $path = '$')
|
||||
* @method $this jsontoggle(string $key, string $path)
|
||||
@@ -270,9 +235,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)
|
||||
@@ -295,7 +257,7 @@ use Predis\Command\Redis\VADD;
|
||||
* @method $this topklist(string $key, bool $withCount = false)
|
||||
* @method $this topkquery(string $key, ...$items)
|
||||
* @method $this topkreserve(string $key, int $topK, int $width = 8, int $depth = 7, float $decay = 0.9)
|
||||
* @method $this tsadd(string $key, int $timestamp, string|float $value, ?AddArguments $arguments = null)
|
||||
* @method $this tsadd(string $key, int $timestamp, float $value, ?AddArguments $arguments = null)
|
||||
* @method $this tsalter(string $key, ?TSAlterArguments $arguments = null)
|
||||
* @method $this tscreate(string $key, ?TSCreateArguments $arguments = null)
|
||||
* @method $this tscreaterule(string $sourceKey, string $destKey, string $aggregator, int $bucketDuration, int $alignTimestamp = 0)
|
||||
@@ -309,29 +271,9 @@ use Predis\Command\Redis\VADD;
|
||||
* @method $this tsmget(MGetArguments $arguments, string ...$filterExpression)
|
||||
* @method $this tsmrange($fromTimestamp, $toTimestamp, MRangeArguments $arguments)
|
||||
* @method $this tsmrevrange($fromTimestamp, $toTimestamp, MRangeArguments $arguments)
|
||||
* @method $this tsnrange(array $keys, $fromTimestamp, $toTimestamp, ?NRangeArguments $arguments = null)
|
||||
* @method $this tsnrevrange(array $keys, $fromTimestamp, $toTimestamp, ?NRangeArguments $arguments = null)
|
||||
* @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 xcfgset(string $key, ?int $duration = null, ?int $maxsize = null)
|
||||
* @method $this xdel(string $key, string ...$id)
|
||||
* @method $this xdelex(string $key, string $mode, array $ids)
|
||||
* @method $this xlen(string $key)
|
||||
* @method $this xnack(string $key, string $group, string $mode, array $ids, ?int $retryCount = null, bool $force = false)
|
||||
* @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 xreadgroup_claim(string $group, string $consumer, array $keyIdDict, ?int $count = null, ?int $blockMs = null, bool $noAck = false, ?int $claim = null)
|
||||
* @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)
|
||||
@@ -373,19 +315,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 vrange(string $key, string $start, string $end, 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)
|
||||
@@ -399,18 +328,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)
|
||||
@@ -421,14 +350,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 HOTKEYS $hotkeys
|
||||
* @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
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
+37
-105
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
@@ -19,7 +19,6 @@ use Predis\Command\Argument\Search\AlterArguments;
|
||||
use Predis\Command\Argument\Search\CreateArguments;
|
||||
use Predis\Command\Argument\Search\DropArguments;
|
||||
use Predis\Command\Argument\Search\ExplainArguments;
|
||||
use Predis\Command\Argument\Search\HybridSearch\HybridSearchQuery;
|
||||
use Predis\Command\Argument\Search\ProfileArguments;
|
||||
use Predis\Command\Argument\Search\SchemaFields\FieldInterface;
|
||||
use Predis\Command\Argument\Search\SearchArguments;
|
||||
@@ -37,24 +36,17 @@ use Predis\Command\Argument\TimeSeries\IncrByArguments;
|
||||
use Predis\Command\Argument\TimeSeries\InfoArguments;
|
||||
use Predis\Command\Argument\TimeSeries\MGetArguments;
|
||||
use Predis\Command\Argument\TimeSeries\MRangeArguments;
|
||||
use Predis\Command\Argument\TimeSeries\NRangeArguments;
|
||||
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\HOTKEYS;
|
||||
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\HSETEX;
|
||||
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\Configuration\OptionsInterface;
|
||||
use Predis\Connection\ConnectionInterface;
|
||||
use Predis\Pipeline\Pipeline;
|
||||
use Predis\Response\Status;
|
||||
|
||||
/**
|
||||
@@ -67,8 +59,6 @@ use Predis\Response\Status;
|
||||
*
|
||||
* @method int copy(string $source, string $destination, int $db = -1, bool $replace = false)
|
||||
* @method int del(string[]|string $keyOrKeys, string ...$keys = null)
|
||||
* @method int delex(string $key, string $flag, $flagValue)
|
||||
* @method string digest(string $key)
|
||||
* @method string|null dump(string $key)
|
||||
* @method int exists(string $key)
|
||||
* @method int expire(string $key, int $seconds, string $expireOption = '')
|
||||
@@ -78,8 +68,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)
|
||||
@@ -89,28 +79,9 @@ use Predis\Response\Status;
|
||||
* @method array sort_ro(string $key, ?string $byPattern = null, ?LimitOffsetCount $limit = null, array $getPatterns = [], ?string $sorting = null, bool $alpha = false)
|
||||
* @method int ttl(string $key)
|
||||
* @method mixed type(string $key)
|
||||
* @method int unlink(string[]|string $keyOrKeys, string ...$keys = null)
|
||||
* @method int append(string $key, $value)
|
||||
* @method int arcount(string $key)
|
||||
* @method int ardel(string $key, int ...$index)
|
||||
* @method int ardelrange(string $key, int ...$startEnd)
|
||||
* @method string|null arget(string $key, int $index)
|
||||
* @method array argetrange(string $key, int $start, int $end)
|
||||
* @method array argrep(string $key, int $start, int $end, array $predicates, ?string $combinator = null, ?int $limit = null, bool $withValues = false, bool $noCase = false)
|
||||
* @method array arinfo(string $key, bool $full = false)
|
||||
* @method int arinsert(string $key, string ...$value)
|
||||
* @method array arlastitems(string $key, int $count, bool $reverse = false)
|
||||
* @method int arlen(string $key)
|
||||
* @method array armget(string $key, int ...$index)
|
||||
* @method int armset(string $key, array $indexValueDictionary)
|
||||
* @method int|null arnext(string $key)
|
||||
* @method mixed arop(string $key, int $start, int $end, string $operation, $matchValue = null)
|
||||
* @method int arring(string $key, int $size, string ...$value)
|
||||
* @method array arscan(string $key, int $start, int $end, ?int $limit = null)
|
||||
* @method int arseek(string $key, int $index)
|
||||
* @method int arset(string $key, int $index, string ...$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)
|
||||
@@ -121,17 +92,16 @@ use Predis\Response\Status;
|
||||
* @method int bitcount(string $key, $start = null, $end = null, string $index = 'byte')
|
||||
* @method int bitop($operation, $destkey, $key)
|
||||
* @method array|null bitfield(string $key, $subcommand, ...$subcommandArg)
|
||||
* @method array|null bitfield_ro(string $key, ?array $encodingOffsetMap = null)
|
||||
* @method int bitpos(string $key, $bit, $start = null, $end = null, string $index = 'byte')
|
||||
* @method array blmpop(int $timeout, array $keys, string $modifier = 'left', int $count = 1)
|
||||
* @method array bzpopmax(array $keys, int $timeout)
|
||||
* @method array bzpopmin(array $keys, int $timeout)
|
||||
* @method array bzmpop(int $timeout, array $keys, string $modifier = 'min', int $count = 1)
|
||||
* @method 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)
|
||||
@@ -150,7 +120,6 @@ use Predis\Response\Status;
|
||||
* @method Status failover(?To $to = null, bool $abort = false, int $timeout = -1)
|
||||
* @method mixed fcall(string $function, array $keys, ...$args)
|
||||
* @method mixed fcall_ro(string $function, array $keys, ...$args)
|
||||
* @method array ft_list()
|
||||
* @method array ftaggregate(string $index, string $query, ?AggregateArguments $arguments = null)
|
||||
* @method Status ftaliasadd(string $alias, string $index)
|
||||
* @method Status ftaliasdel(string $alias)
|
||||
@@ -162,7 +131,6 @@ use Predis\Response\Status;
|
||||
* @method array ftdictdump(string $dict)
|
||||
* @method Status ftdropindex(string $index, ?DropArguments $arguments = null)
|
||||
* @method string ftexplain(string $index, string $query, ?ExplainArguments $arguments = null)
|
||||
* @method array fthybrid(string $index, HybridSearchQuery $query)
|
||||
* @method array ftinfo(string $index)
|
||||
* @method array ftprofile(string $index, ProfileArguments $arguments)
|
||||
* @method array ftsearch(string $index, string $query, ?SearchArguments $arguments = null)
|
||||
@@ -183,13 +151,11 @@ use Predis\Response\Status;
|
||||
* @method int incr(string $key)
|
||||
* @method int incrby(string $key, int $increment)
|
||||
* @method string incrbyfloat(string $key, int|float $increment)
|
||||
* @method array increx(string $key, int|float|string $value, ?int $lbound = null, ?int $ubound = null, bool $saturate = false, ?string $expireType = null, $expireValue = null, bool $enx = false)
|
||||
* @method array mget(string[]|string $keyOrKeys, string ...$keys = null)
|
||||
* @method mixed mset(array $dictionary)
|
||||
* @method array msetex(array $dictionary, ?string $existModifier = null, ?string $expireResolution = null, ?int $expireTTL = null)
|
||||
* @method int msetnx(array $dictionary)
|
||||
* @method Status psetex(string $key, $milliseconds, $value)
|
||||
* @method Status|null set(string $key, $value, $expireResolution = null, $expireTTL = null, $flag = null, $flagValue = null)
|
||||
* @method Status|null set(string $key, $value, $expireResolution = null, $expireTTL = null, $flag = null)
|
||||
* @method int setbit(string $key, $offset, $value)
|
||||
* @method Status setex(string $key, $seconds, $value)
|
||||
* @method int setnx(string $key, $value)
|
||||
@@ -205,9 +171,7 @@ use Predis\Response\Status;
|
||||
* @method array|null hpexpireat(string $key, int $unixTimeMilliseconds, array $fields, string $flag = null)
|
||||
* @method array|null hpexpiretime(string $key, array $fields)
|
||||
* @method string|null hget(string $key, string $field)
|
||||
* @method array|null hgetex(string $key, array $fields, string $modifier = HGETEX::NULL, int|bool $modifierValue = false)
|
||||
* @method array hgetall(string $key)
|
||||
* @method array hgetdel(string $key, array $fields)
|
||||
* @method int hincrby(string $key, string $field, int $increment)
|
||||
* @method string hincrbyfloat(string $key, string $field, int|float $increment)
|
||||
* @method array hkeys(string $key)
|
||||
@@ -217,7 +181,6 @@ use Predis\Response\Status;
|
||||
* @method array hrandfield(string $key, int $count = 1, bool $withValues = false)
|
||||
* @method array hscan(string $key, $cursor, ?array $options = null)
|
||||
* @method int hset(string $key, string $field, string $value)
|
||||
* @method int hsetex(string $key, array $fieldValueMap, string $setModifier = HSETEX::SET_NULL, string $ttlModifier = HSETEX::TTL_NULL, int|bool $ttlModifierValue = false)
|
||||
* @method int hsetnx(string $key, string $field, string $value)
|
||||
* @method array|null httl(string $key, array $fields)
|
||||
* @method array|null hpttl(string $key, array $fields)
|
||||
@@ -232,15 +195,15 @@ 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)
|
||||
* @method array jsonobjkeys(string $key, string $path = '$')
|
||||
* @method array jsonobjlen(string $key, string $path = '$')
|
||||
* @method array jsonresp(string $key, string $path = '$')
|
||||
* @method string jsonset(string $key, string $path, string $value, ?string $subcommand = null, ?string $fpha = null)
|
||||
* @method string jsonset(string $key, string $path, string $value, ?string $subcommand = null)
|
||||
* @method array jsonstrappend(string $key, string $path, string $value)
|
||||
* @method array jsonstrlen(string $key, string $path = '$')
|
||||
* @method array jsontoggle(string $key, string $path)
|
||||
@@ -280,12 +243,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)
|
||||
@@ -293,10 +253,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)
|
||||
@@ -307,7 +267,7 @@ use Predis\Response\Status;
|
||||
* @method array topklist(string $key, bool $withCount = false)
|
||||
* @method array topkquery(string $key, ...$items)
|
||||
* @method Status topkreserve(string $key, int $topK, int $width = 8, int $depth = 7, float $decay = 0.9)
|
||||
* @method int tsadd(string $key, int $timestamp, string|float $value, ?AddArguments $arguments = null)
|
||||
* @method int tsadd(string $key, int $timestamp, float $value, ?AddArguments $arguments = null)
|
||||
* @method Status tsalter(string $key, ?TSAlterArguments $arguments = null)
|
||||
* @method Status tscreate(string $key, ?TSCreateArguments $arguments = null)
|
||||
* @method Status tscreaterule(string $sourceKey, string $destKey, string $aggregator, int $bucketDuration, int $alignTimestamp = 0)
|
||||
@@ -321,32 +281,19 @@ use Predis\Response\Status;
|
||||
* @method array tsmget(MGetArguments $arguments, string ...$filterExpression)
|
||||
* @method array tsmrange($fromTimestamp, $toTimestamp, MRangeArguments $arguments)
|
||||
* @method array tsmrevrange($fromTimestamp, $toTimestamp, MRangeArguments $arguments)
|
||||
* @method array tsnrange(array $keys, $fromTimestamp, $toTimestamp, ?NRangeArguments $arguments = null)
|
||||
* @method array tsnrevrange(array $keys, $fromTimestamp, $toTimestamp, ?NRangeArguments $arguments = null)
|
||||
* @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 Status xcfgset(string $key, ?int $duration = null, ?int $maxsize = 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 int xnack(string $key, string $group, string $mode, array $ids, ?int $retryCount = null, bool $force = false)
|
||||
* @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 array xreadgroup_claim(string $group, string $consumer, array $keyIdDict, ?int $count = null, ?int $blockMs = null, bool $noAck = false, ?int $claim = null)
|
||||
* @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)
|
||||
* @method string zcount(string $key, int|string $min, int|string $max)
|
||||
* @method array zdiff(array $keys, bool $withScores = false)
|
||||
* @method int zdiffstore(string $destination, array $keys)
|
||||
* @method string zincrby(string $key, int $increment, string $member)
|
||||
@@ -385,21 +332,7 @@ use Predis\Response\Status;
|
||||
* @method mixed discard()
|
||||
* @method array|null exec()
|
||||
* @method mixed multi()
|
||||
* @method Pipeline|array pipeline(mixed ...$arguments)
|
||||
* @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 array vrange(string $key, string $start, string $end, 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)
|
||||
@@ -414,18 +347,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)
|
||||
@@ -436,15 +369,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 HOTKEYS $hotkeys
|
||||
* @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
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
@@ -42,7 +42,6 @@ abstract class ClusterStrategy implements StrategyInterface
|
||||
/* commands operating on the key space */
|
||||
'EXISTS' => $getKeyFromAllArguments,
|
||||
'DEL' => $getKeyFromAllArguments,
|
||||
'UNLINK' => $getKeyFromAllArguments,
|
||||
'TYPE' => $getKeyFromFirstArgument,
|
||||
'EXPIRE' => $getKeyFromFirstArgument,
|
||||
'EXPIREAT' => $getKeyFromFirstArgument,
|
||||
@@ -69,7 +68,6 @@ abstract class ClusterStrategy implements StrategyInterface
|
||||
'INCR' => $getKeyFromFirstArgument,
|
||||
'INCRBY' => $getKeyFromFirstArgument,
|
||||
'INCRBYFLOAT' => $getKeyFromFirstArgument,
|
||||
'INCREX' => $getKeyFromFirstArgument,
|
||||
'SETBIT' => $getKeyFromFirstArgument,
|
||||
'SETEX' => $getKeyFromFirstArgument,
|
||||
'MSET' => [$this, 'getKeyFromInterleavedArguments'],
|
||||
@@ -101,26 +99,6 @@ abstract class ClusterStrategy implements StrategyInterface
|
||||
'LSET' => $getKeyFromFirstArgument,
|
||||
'LTRIM' => $getKeyFromFirstArgument,
|
||||
|
||||
/* commands operating on arrays */
|
||||
'ARCOUNT' => $getKeyFromFirstArgument,
|
||||
'ARDEL' => $getKeyFromFirstArgument,
|
||||
'ARDELRANGE' => $getKeyFromFirstArgument,
|
||||
'ARGET' => $getKeyFromFirstArgument,
|
||||
'ARGETRANGE' => $getKeyFromFirstArgument,
|
||||
'ARGREP' => $getKeyFromFirstArgument,
|
||||
'ARINFO' => $getKeyFromFirstArgument,
|
||||
'ARINSERT' => $getKeyFromFirstArgument,
|
||||
'ARLASTITEMS' => $getKeyFromFirstArgument,
|
||||
'ARLEN' => $getKeyFromFirstArgument,
|
||||
'ARMGET' => $getKeyFromFirstArgument,
|
||||
'ARMSET' => $getKeyFromFirstArgument,
|
||||
'ARNEXT' => $getKeyFromFirstArgument,
|
||||
'AROP' => $getKeyFromFirstArgument,
|
||||
'ARRING' => $getKeyFromFirstArgument,
|
||||
'ARSCAN' => $getKeyFromFirstArgument,
|
||||
'ARSEEK' => $getKeyFromFirstArgument,
|
||||
'ARSET' => $getKeyFromFirstArgument,
|
||||
|
||||
/* commands operating on sets */
|
||||
'SADD' => $getKeyFromFirstArgument,
|
||||
'SCARD' => $getKeyFromFirstArgument,
|
||||
@@ -153,7 +131,6 @@ abstract class ClusterStrategy implements StrategyInterface
|
||||
'ZREVRANGEBYSCORE' => $getKeyFromFirstArgument,
|
||||
'ZREVRANK' => $getKeyFromFirstArgument,
|
||||
'ZSCORE' => $getKeyFromFirstArgument,
|
||||
'ZMSCORE' => $getKeyFromFirstArgument,
|
||||
'ZUNIONSTORE' => [$this, 'getKeyFromZsetAggregationCommands'],
|
||||
'ZSCAN' => $getKeyFromFirstArgument,
|
||||
'ZLEXCOUNT' => $getKeyFromFirstArgument,
|
||||
@@ -178,11 +155,6 @@ abstract class ClusterStrategy implements StrategyInterface
|
||||
'HSCAN' => $getKeyFromFirstArgument,
|
||||
'HSTRLEN' => $getKeyFromFirstArgument,
|
||||
|
||||
/* commands operating on streams */
|
||||
'XADD' => $getKeyFromFirstArgument,
|
||||
'XDEL' => $getKeyFromFirstArgument,
|
||||
'XRANGE' => $getKeyFromFirstArgument,
|
||||
|
||||
/* commands operating on HyperLogLog */
|
||||
'PFADD' => $getKeyFromFirstArgument,
|
||||
'PFCOUNT' => $getKeyFromAllArguments,
|
||||
@@ -205,16 +177,8 @@ abstract class ClusterStrategy implements StrategyInterface
|
||||
'GEORADIUS' => [$this, 'getKeyFromGeoradiusCommands'],
|
||||
'GEORADIUSBYMEMBER' => [$this, 'getKeyFromGeoradiusCommands'],
|
||||
|
||||
/* sharded pubsub */
|
||||
'SSUBSCRIBE' => $getKeyFromAllArguments,
|
||||
'SUNSUBSCRIBE' => [$this, 'getKeyFromSUnsubscribeCommand'],
|
||||
'SPUBLISH' => $getKeyFromFirstArgument,
|
||||
|
||||
/* cluster */
|
||||
'CLUSTER' => [$this, 'getFakeKey'],
|
||||
|
||||
/* control */
|
||||
'ACL' => [$this, 'getFakeKey'],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -443,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.
|
||||
*
|
||||
@@ -501,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;
|
||||
@@ -517,6 +467,8 @@ abstract class ClusterStrategy implements StrategyInterface
|
||||
if ($currentSlot !== $nextSlot) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$currentSlot = $nextSlot;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
@@ -16,7 +16,7 @@ use Predis\Cluster\Hash\HashGeneratorInterface;
|
||||
|
||||
/**
|
||||
* This class implements an hashring-based distributor that uses the same
|
||||
* algorithm of memcached to distribute keys in a cluster using client-side
|
||||
* algorithm of memcache to distribute keys in a cluster using client-side
|
||||
* sharding.
|
||||
* @author Lorenzo Castelli <lcastelli@gmail.com>
|
||||
*/
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 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;
|
||||
|
||||
/**
|
||||
* Represents the gap between slot ranges.
|
||||
*/
|
||||
class NullSlotRange extends SlotRange
|
||||
{
|
||||
public function __construct(int $start, int $end)
|
||||
{
|
||||
parent::__construct($start, $end, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function count(): int
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
@@ -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;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 Till Krüss
|
||||
* (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.
|
||||
|
||||
@@ -1,209 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2026 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;
|
||||
|
||||
use ArrayAccess;
|
||||
use ArrayIterator;
|
||||
use Countable;
|
||||
use IteratorAggregate;
|
||||
use OutOfBoundsException;
|
||||
use Predis\Connection\NodeConnectionInterface;
|
||||
use ReturnTypeWillChange;
|
||||
use Traversable;
|
||||
|
||||
/**
|
||||
* Slot map for redis-cluster.
|
||||
*/
|
||||
class SimpleSlotMap implements ArrayAccess, IteratorAggregate, Countable
|
||||
{
|
||||
private $slots = [];
|
||||
|
||||
/**
|
||||
* Checks if the given slot is valid.
|
||||
*
|
||||
* @param int $slot Slot index.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isValid($slot)
|
||||
{
|
||||
return $slot >= 0x0000 && $slot <= 0x3FFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given slot range is valid.
|
||||
*
|
||||
* @param int $first Initial slot of the range.
|
||||
* @param int $last Last slot of the range.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isValidRange($first, $last)
|
||||
{
|
||||
return $first >= 0x0000 && $first <= 0x3FFF && $last >= 0x0000 && $last <= 0x3FFF && $first <= $last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the slot map.
|
||||
*/
|
||||
public function reset()
|
||||
{
|
||||
$this->slots = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the slot map is empty.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmpty()
|
||||
{
|
||||
return empty($this->slots);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current slot map as a dictionary of $slot => $node.
|
||||
*
|
||||
* The order of the slots in the dictionary is not guaranteed.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
return $this->slots;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of unique nodes in the slot map.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getNodes()
|
||||
{
|
||||
return array_keys(array_flip($this->slots));
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the specified slot range to a node.
|
||||
*
|
||||
* @param int $first Initial slot of the range.
|
||||
* @param int $last Last slot of the range.
|
||||
* @param NodeConnectionInterface|string $connection ID or connection instance.
|
||||
*
|
||||
* @throws OutOfBoundsException
|
||||
*/
|
||||
public function setSlots($first, $last, $connection)
|
||||
{
|
||||
if (!static::isValidRange($first, $last)) {
|
||||
throw new OutOfBoundsException("Invalid slot range $first-$last for `$connection`");
|
||||
}
|
||||
|
||||
$this->slots += array_fill($first, $last - $first + 1, (string) $connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the specified slot range.
|
||||
*
|
||||
* @param int $first Initial slot of the range.
|
||||
* @param int $last Last slot of the range.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getSlots($first, $last)
|
||||
{
|
||||
if (!static::isValidRange($first, $last)) {
|
||||
throw new OutOfBoundsException("Invalid slot range $first-$last");
|
||||
}
|
||||
|
||||
return array_intersect_key($this->slots, array_fill($first, $last - $first + 1, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the specified slot is assigned.
|
||||
*
|
||||
* @param int $slot Slot index.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function offsetExists($slot)
|
||||
{
|
||||
return isset($this->slots[$slot]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the node assigned to the specified slot.
|
||||
*
|
||||
* @param int $slot Slot index.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function offsetGet($slot)
|
||||
{
|
||||
return $this->slots[$slot] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the specified slot to a node.
|
||||
*
|
||||
* @param int $slot Slot index.
|
||||
* @param NodeConnectionInterface|string $connection ID or connection instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function offsetSet($slot, $connection)
|
||||
{
|
||||
if (!static::isValid($slot)) {
|
||||
throw new OutOfBoundsException("Invalid slot $slot for `$connection`");
|
||||
}
|
||||
|
||||
$this->slots[(int) $slot] = (string) $connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the node assigned to the specified slot.
|
||||
*
|
||||
* @param int $slot Slot index.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function offsetUnset($slot)
|
||||
{
|
||||
unset($this->slots[$slot]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current number of assigned slots.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function count()
|
||||
{
|
||||
return count($this->slots);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator over the slot map.
|
||||
*
|
||||
* @return Traversable<int, string>
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function getIterator()
|
||||
{
|
||||
return new ArrayIterator($this->slots);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user